2013-02-28 13 views
25

私のモデル 'Products'を保存すると、アップロードした画像の名前をpkと同じ名前にします22.pngまたは34.gif形式を変更したくありませんイメージはちょうど名前。これはどうすればできますか?これまでに以下の私のモデルの一例...Django ImageFieldはアップロード時にファイル名を変更します

image = models.ImageField(
     upload_to="profiles", 
     height_field="image_height", 
     width_field="image_width", 
     null=True, 
     blank=True, 
     editable=True, 
     help_text="Profile Picture", 
     verbose_name="Profile Picture" 
    ) 
    image_height = models.PositiveIntegerField(null=True, blank=True, editable=False, default="100") 
    image_width = models.PositiveIntegerField(null=True, blank=True, editable=False, default="100") 

答えて

57

あなたはupload_toフィールドに関数を渡すことができます。

def f(instance, filename): 
    ext = filename.split('.')[-1] 
    if instance.pk: 
     return '{}.{}'.format(instance.pk, ext) 
    else: 
     pass 
     # do something if pk is not there yet 

私の提案は{pk}.{ext}の代わりにランダムなファイル名を返すようになります。ボーナスとして、より安全になります。

Djangoはファイルをアップロードする場所を決定するためにこの関数を呼び出します。これは、関数がファイル名を含むファイルの全パスを返す責任があることを意味します。以下は、あなたがにアップロードすると、その使用方法を指定することができる機能が変更されます。

import os 
from uuid import uuid4 

def path_and_rename(path): 
    def wrapper(instance, filename): 
     ext = filename.split('.')[-1] 
     # get filename 
     if instance.pk: 
      filename = '{}.{}'.format(instance.pk, ext) 
     else: 
      # set filename as random string 
      filename = '{}.{}'.format(uuid4().hex, ext) 
     # return the whole path to the file 
     return os.path.join(path, filename) 
    return wrapper 

FileField(upload_to=path_and_rename('upload/here/'), ...) 
+1

は、関数に私を打つ:( –

+0

申し訳ありません。私は実際にあなたの答えを見ていない。私は投稿時にも地雷が別の答えがあったことに気づいた... – miki725

+0

インスタンスが渡されていることがモデルだろうか? – jason

5

docsで説明したようにあなたが呼び出し可能でupload_toに文字列あなたの割り当てを置き換えることができます。しかし、upload_toパラメータが使用されている時点でプライマリキーが利用できない可能性があります。

16

ジャンゴ1.7以降、このような機能を移行することはありません。 @ miki275によって解答とthisチケットに基づいて、あなたはこのようにあなたの関数を作成する必要があります。

import os 
from uuid import uuid4 
from django.utils.deconstruct import deconstructible 

@deconstructible 
class UploadToPathAndRename(object): 

    def __init__(self, path): 
     self.sub_path = path 

    def __call__(self, instance, filename): 
     ext = filename.split('.')[-1] 
     # get filename 
     if instance.pk: 
      filename = '{}.{}'.format(instance.pk, ext) 
     else: 
      # set filename as random string 
      filename = '{}.{}'.format(uuid4().hex, ext) 
     # return the whole path to the file 
     return os.path.join(self.sub_path, filename) 

FileField(upload_to=UploadToPathAndRename(os.path.join(MEDIA_ROOT, 'upload', 'here'), ...) 
+0

これはPython 2.7(Django 1.9のテスト版)でも有効ですが、 Python 2の制限により、バインドされていないメソッド関数(例えば、同じクラス本体で宣言され使用されているメソッド)を直列化することはできません。移行を使用するには、この機能をメインモジュール本体に移動してください。 詳細については、https:// docs.djangoproject.com/ja/1.9/topics/migrations /#serializing-values'を参照してください。 – dotcomly

0

別のオプション我々は%Y/%m/%dでパスを返す必要がある場合、この答えhttps://stackoverflow.com/a/15141228/3445802次のように、私たちは、問題を発見した例:

FileField(upload_to=path_and_rename('upload/here/%Y/%m/%d'), ...) 

ので、我々はこれでそれを扱う:

FileField(upload_to=path_and_rename('upload/here/{}'.format(time.strftime("%Y/%m/%d"))), ...) 

Makesurモジュールtimeがインポートされました。

関連する問題