29

FileFieldユーザーがアップロードしたファイルを保持するを持つモデルがあります。スペースを節約したいので、重複は避けたいです。

私が達成したいこと:

  1. アップロードされたファイルのmd5 チェックサムを計算する
  2. md5sum に基づいたファイル名でファイルを保存します
  3. その名前のファイルが既に存在する場合 (新しいファイルは重複しています)、アップロードされたファイルを破棄し、代わりに既存のファイルを使用します

12は既に機能していますが、アップロードされた複製を忘れて、代わりに既存のファイルを使用するにはどうすればよいでしょうか?

既存のファイルを保持し、上書きしないようにしたいことに注意してください(主に、変更された時間を同じに保つため-バックアップに適しています)。

ノート:

  • 私はDjango 1.5を使用しています
  • アップロードハンドラはdjango.core.files.uploadhandler.TemporaryFileUploadHandler

コード:

def media_file_name(instance, filename):
    h = instance.md5sum
    basename, ext = os.path.splitext(filename)
    return os.path.join('mediafiles', h[0:1], h[1:2], h + ext.lower())

class Media(models.Model):
    orig_file = models.FileField(upload_to=media_file_name)
    md5sum = models.CharField(max_length=36)
    ...

    def save(self, *args, **kwargs):
            if not self.pk:  # file is new
                md5 = hashlib.md5()
                for chunk in self.orig_file.chunks():
                    md5.update(chunk)
                self.md5sum = md5.hexdigest()
            super(Media, self).save(*args, **kwargs)

どんな助けでも大歓迎です!

4

5 に答える 5

9

私の知る限り、保存/削除メソッドを使用してこれを簡単に実装することはできません.cozファイルは非常に具体的に処理されます。

しかし、あなたはそのように試すことができます。

まず、私の単純な md5 ファイル ハッシュ関数:

def md5_for_file(chunks):
    md5 = hashlib.md5()
    for data in chunks:
        md5.update(data)
    return md5.hexdigest()

simple_upload_toは、あなたの media_file_name 関数のようなものです。次のように使用する必要があります。

def simple_upload_to(field_name, path='files'):
    def upload_to(instance, filename):
        name = md5_for_file(getattr(instance, field_name).chunks())
        dot_pos = filename.rfind('.')
        ext = filename[dot_pos:][:10].lower() if dot_pos > -1 else '.unknown'
        name += ext
        return os.path.join(path, name[:2], name)
    return upload_to

class Media(models.Model):
    # see info about storage below
    orig_file = models.FileField(upload_to=simple_upload_to('orig_file'), storage=MyCustomStorage())

もちろん、これは一例ですので、パスの生成ロジックはさまざまです。

そして最も重要な部分:

from django.core.files.storage import FileSystemStorage

class MyCustomStorage(FileSystemStorage):
    def get_available_name(self, name):
        return name

    def _save(self, name, content):
        if self.exists(name):
            self.delete(name)
        return super(MyCustomStorage, self)._save(name, content)

ご覧のとおり、このカスタム ストレージはファイルを保存する前に削除し、新しいファイルを同じ名前で保存します。したがって、ファイルを削除しない(したがって更新しない)ことが重要な場合は、ここでロジックを実装できます。

ここで見つけることができるストレージの詳細: https://docs.djangoproject.com/en/1.5/ref/files/storage/

于 2013-04-08T21:39:38.390 に答える