Django ImageField change file name on upload

前端 未结 5 1564
没有蜡笔的小新
没有蜡笔的小新 2021-01-30 04:35

Upon saving me model \'Products\' I would like the uploaded image to be named the same as the pk for example 22.png or 34.gif I don\'t want to change the format of the image jus

相关标签:
5条回答
  • 2021-01-30 04:44

    Django 1.7 and newer won't make migration with function like this. Based on answer by @miki725 and this ticket, you need to make your function like 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 讨论(0)
  • 2021-01-30 04:50

    You can replace the string your assigning to upload_to with a callable as described in the docs. However, I suspect the primary key may not be available at the point the upload_to parameter is used.

    0 讨论(0)
  • 2021-01-30 04:51

    By default Django keeps the original name of the uploaded file but more than likely you will want to rename it to something else (like the object's id). Luckily, with ImageField or FileField of Django forms, you can assign a callable function to the upload_to parameter to do the renaming. For example:

    from django.db import models
    from django.utils import timezone
    import os
    from uuid import uuid4
    
    def path_and_rename(instance, filename):
        upload_to = 'photos'
        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(upload_to, filename)
    

    and in models field:

    class CardInfo(models.Model):
        ...
        photo = models.ImageField(upload_to=path_and_rename, max_length=255, null=True, blank=True)
    

    In this example, every image that is uploaded will be rename to the CardInfo object's primary key which is id_number.

    0 讨论(0)
  • 2021-01-30 04:54

    Another option, as following this answer https://stackoverflow.com/a/15141228/3445802, we found the issue when we need return path with %Y/%m/%d, example:

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

    so, we handle it with this:

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

    Makesure the module time has been imported.

    0 讨论(0)
  • 2021-01-30 04:58

    You can pass a function into upload_to field:

    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
    

    My suggestions would be to return a random filename instead of {pk}.{ext}. As a bonus, it will be more secure.

    What happens is that Django will call this function to determine where the file should be uploaded to. That means that your function is responsible for returning the whole path of the file including the filename. Below is modified function where you can specify where to upload to and how to use it:

    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/'), ...)
    
    0 讨论(0)
提交回复
热议问题