Как получить имя поля FileField в методе upload_to, для поля, переведенного с помощью перевода модели в Django? - PullRequest
2 голосов
/ 23 января 2020

Я использую django модель перевода на FileField.

Я бы хотел, чтобы этот файл был загружен по пути /path/to/file/<lang>/file.ext, и я думаю, что лучший способ - извлечь язык из имени поля (file_en, file_it, file_fr, ...), где upload_to - это эксплуатации.

# 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", )

Ответы [ 2 ]

1 голос
/ 23 января 2020

Что-то вроде этого должно работать.

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)

Он использует самоанализ для динамического переопределения параметра upload_to каждого специфицированного языка c FileField, генерируемого django -modeltranslation за сценой.

С этой моделью, например:

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 определены en и fr.

Если параметр upload_to, переданный в FileField, был путь в виде строки, он переопределяется тем же путем, в который вставляется папка для языка. Если это функция, то папка для языка вставляется в путь, возвращаемый этой функцией.

Например, если у вас есть

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)

, то в обоих случаях:

  • версия файла Engli sh будет сохранена в /path/to/en/file.png
  • французской версии файл будет сохранен в /path/to/fr/file.png
0 голосов
/ 23 января 2020

Попробуйте использовать 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"
...