【问题标题】:Django Adding Prefix to FileFieldDjango 为 FileField 添加前缀
【发布时间】:2018-10-03 07:58:23
【问题描述】:

我有一个模型可以接收多个 pdf 文件。当用户上传这些文件时,我希望每个文件都用前缀和一些随机字符重命名。我可以将 upload_to 分配给可调用的函数,例如:

class Order(models.Model):
    invoice_file = models.FileField(upload_to=invoice_file_name)
    purchase_order_file = models.FileField( upload_to=po_file_name)
    payment_file = models.FileField( upload_to=payment_file_name)

def invoice_file_name(instance, file_name):
    return 'inv_' + str(uuid.uuid4()) + '.pdf'

def po_file_name(instance, file_name):
    return 'po_' + str(uuid.uuid4()) + '.pdf'

def payment_file_name(instance, file_name):
    return 'pmt_' + str(uuid.uuid4()) + '.pdf'

有没有办法概括这些 upload_to 函数,以便我可以在 FileField 定义中传递前缀?

尝试:

我试图通过创建一个扩展 FileField 的自定义文件字段来解决这个问题

class CustomFileField(models.FileField):
    def __init__(self, file_prefix, **kwargs):
        self.file_prefix = file_prefix
        # print(kwargs)
        super().__init__(upload_to=self.custom_upload_to, **kwargs)

    def custom_upload_to(self, file_name):
        return self.file_prefix + str(uuid.uuid4()) + '.pdf' 


class Order(models.Model):
    invoice_file = CustomFileField(file_prefix='inv_')
    purchase_order_file = CustomFileField(file_prefix='po_')
    payment_file = CustomFileField(file_prefix='pmt_')

但是,迁移失败。其中一个错误是

TypeError: __init__() got multiple values for keyword argument 'upload_to'

不太清楚发生了什么,但我查看了迁移文件,它似乎在调用这个:

migrations.CreateModel(
    name='Order',
    fields=[
        ('invoice_file', CustomFileField(blank=True, null=True, upload_to='')
        ...
    ])

这是对 FileField 进行子类化的错误方式吗?

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    你可以不用CustomFileField 而是用@deconstructible 来做到这一点

    from django.utils.deconstruct import deconstructible
    from django.db import models
    
    
    @deconstructible
    class file_prefix(object):
        def __init__(self, prefix):
            self.prefix = prefix
    
        def __call__(self, instance, filename):
            ext = filename.split('.')[-1] # PDF if you want
            filename = "%s%s.%s" % (self.prefix,str(uuid.uuid4()), ext)
            return filename
    

    例如,调用upload_to时默认发送文件名,所以我们只发送前缀。

    class Order(models.Model):
        invoice_file = models.FileField(upload_to=file_prefix('inv_'))
        purchase_order_file = models.FileField(upload_to=file_prefix('po_'))
        payment_file = models.FileField(upload_to=file_prefix('pmt_'))
    

    【讨论】:

    • 不是 100% 确定 @deconstructible 是做什么的,但这是可行的。迁移没有问题
    • 更多信息 --> django doc
    【解决方案2】:

    这是有效的:

    class CustomFileField(models.FileField):
        def __init__(self, file_prefix = '', null=True, blank=True, upload_to='', **kwargs):
            self.file_prefix = file_prefix
            super().__init__(upload_to=self.custom_upload_to, **kwargs)
    
        def custom_upload_to(self, instance, file_name):
            return self.file_prefix + str(uuid.uuid4()) + '.pdf' 
    
    
    class Order(models.Model):
        invoice_file = CustomFileField(file_prefix='inv_')
        purchase_order_file = CustomFileField(file_prefix='po_')
        payment_file = CustomFileField(file_prefix='pmt_')
    

    迁移序列化程序似乎要查找 3 个参数:null、blank 和 upload_to,所以我需要在我的 CustomFileField 初始化函数中包含这些参数。

    【讨论】:

    • 这在 DRF 中不起作用,它会保持创建迁移步骤
    猜你喜欢
    • 2018-12-12
    • 1970-01-01
    • 2018-08-09
    • 2012-04-03
    • 2015-07-30
    • 2018-08-19
    • 2013-01-30
    • 1970-01-01
    相关资源
    最近更新 更多