【问题标题】:How to get the fieldname of a FileField in the upload_to method, for a field translated with modeltranslation in Django?对于在Django中使用modeltranslation翻译的字段,如何在upload_to方法中获取FileField的字段名?
【发布时间】:2020-05-09 22:13:19
【问题描述】:

我在 FileField 上使用 django 模型翻译。

我希望将此文件上传到路径/path/to/file/<lang>/file.ext,我想最好的方法是从upload_to 正在运行的字段名(file_en、file_it、file_fr、...)中提取语言。

# models.py
def upload_method(instance, filename):
   lang = ""  # how to get this variable? 
   return f"/path/to/file/{lang}/file.ext"

class Obj(models.Model):
   file = models.FileField(upload_to=upload_method)

# translation.py
@register(models.Obj)
class ObjTranslationOptions(TranslationOptions):
    fields = ("file", )

【问题讨论】:

    标签: python django django-models django-file-upload django-modeltranslation


    【解决方案1】:

    尝试使用get_language方法:

    from django.utils.translation import get_language
    
    def upload_method(instance, filename):
       lang = get_language()
       return f"/path/to/file/{lang}/file.ext"
    

    【讨论】:

    • 我不能,因为 get_language() 正在使用当前用户的语言。想象一下,我是一名使用意大利语的管理员,我想上传一个法语文件。在 upload_to 评估中,get_language() 将返回“it”
    【解决方案2】:

    这样的事情应该可以工作。

    from modeltranslation.translator import translator
    from django.db.models import FileField
    import os
    
    
    class TranslationMeta(type):
        def __init__(self, name, bases, attrs):
            for attrname, attrvalue in attrs.items():
                if self.is_translated_field(name, attrname):
                    field = attrvalue
                    if isinstance(field, FileField):
                        self.update_upload_to(field, attrname)
            super().__init__(name, bases, attrs)
    
        def is_translated_field(self, class_name, attr_name):
            opts = translator.get_options_for_model(self)
            return attr_name in opts.get_field_names()
    
        def update_upload_to(self, field, attr_name):
            opts = translator.get_options_for_model(self)
            translated_fields = opts.fields[attr_name]
            for trans_field in translated_fields:
                # print(trans_field.name)
                # print(trans_field.language)
                trans_field.upload_to = self.custom_upload_to(field.upload_to, trans_field.language)    
    
        def custom_upload_to(self, base_upload_to, language):
            # If the original upload_to parameter is a callable,
            # return a function that calls the original upload_to
            # function and inserts the language as the final folder
            # in the path
            # If the original upload_to function returned /path/to/file.png,
            # then the final path will be /path/to/en/file.png for the
            # english field
            if callable(base_upload_to):
                def upload_to(instance, filename):
                    path = base_upload_to(instance, filename)
                    return os.path.join(
                        os.path.dirname(path),
                        language,
                        os.path.basename(path))
                return upload_to
            # If the original upload_to parameter is a path as a string,
            # insert the language as the final folder in the path
            # /path/to/file.png becomes /path/to/en/file.png for the
            # english field
            else:
                return os.path.join(
                    os.path.dirname(base_upload_to),
                    language,
                    os.path.basename(base_upload_to))
    
    
    # This is how you would use this class
    class MyModel(models.Model, metaclass=TranslationMeta):
        field = FileField()
    
    m = MyModel(models.Model)
    print(m.field.upload_to)
    

    它使用自省来动态覆盖由 django-modeltranslation 在后台生成的每个特定语言 FileField 的 upload_to 参数。

    以这个模型为例:

    class MyModel(models.Model):
        field = FileField(upload_to=...)
    

    如果您已通过添加将field 定义为可翻译字段

    from modeltranslation.translator import register, TranslationOptions
    from . import models
    
    @register(models.MyModel)
    class MyModelTranslationOptions(TranslationOptions):
        fields = ("field",)
    

    translation.py 中,django-modeltranslation 会生成类似

    class MyModel(models.Model):
        field = FileField(upload_to=...)
        field_en = FileField(upload_to=...)
        field_fr = FileField(upload_to=...)
    

    如果您在LANGUAGES 设置中定义了enfr

    如果传递给 FileField 的 upload_to 参数是作为字符串的路径,则使用插入该语言的文件夹的相同路径覆盖它。 如果是函数,则该语言的文件夹插入到该函数返回的路径中。

    例如,如果你有

    class MyModel(models.Model):
        field = FileField(upload_to="/path/to/file.png")
    

    def get_upload_path(instance, filename):
        return "path/to/file.png"
    
    class MyModel(models.Model):
        field = FileField(upload_to=get_upload_path)
    

    那么,在这两种情况下:

    • 文件的英文版本将存储在 /path/to/en/file.png 下
    • 文件的法语版本将存储在 /path/to/fr/file.png 下

    【讨论】:

    • 我认为你应该向 django modeltranslation 老兄提出拉取请求!
    猜你喜欢
    • 2018-04-22
    • 2020-11-05
    • 2020-04-16
    • 2018-11-13
    • 1970-01-01
    • 2018-07-04
    • 2015-09-05
    • 1970-01-01
    • 2012-12-30
    相关资源
    最近更新 更多