如何正确地动态添加启用django-modeltranslation的ModelForm字段?

tquggr8v  于 2023-08-08  发布在  Go
关注(0)|答案(1)|浏览(97)

我正在尝试动态地为我的forms.ModelForm添加可翻译字段,具体取决于客户是否启用了该语言。但是,转换后的值不会保存到模型中。

from copy import deepcopy
from django import forms
from modeltranslation.fields import TranslationField

class DefaultModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if user := self.request and self.request.user:
            company = user.company
            app_setting = company.settings
            default_lang = settings.MODELTRANSLATION_DEFAULT_LANGUAGE  # "en"
            default_search = f"_{default_lang}"
            to_add = []
            """Set field_order to the same order as set in Meta.fields, unless already set"""
            if self.field_order is None:
                self.field_order = list(self.Meta.fields)

            for modelfield in self._meta.model._meta.fields:
                """If we found a default translation field, add it to the list"""
                if (
                    (formfield := self.fields.get(modelfield.name, None))
                    and modelfield.name.endswith(default_search)
                    and isinstance(modelfield, TranslationField)
                ):
                    to_add.append(
                        {
                            "position": self.field_order.index(modelfield.name),
                            "formfield": deepcopy(formfield),
                            "name": modelfield.name.removesuffix(default_search),  # "description"
                            "languages": app_setting.get_additional_language_codes,  # ["es"]
                        }
                    )

            for addable in to_add:
                for lang in addable.get("languages"):
                    field_name = f"{addable.get('name')}_{lang}"  # "description_es"
                    formfield = addable.get("formfield")
                    formfield.label = formfield.label.replace(f"[{default_lang}]", f"[{lang}]")
                    formfield.required = False
                    formfield.initial = getattr(self.instance, field_name, "")

                    self.fields[field_name] = formfield
                    self.field_order.insert(addable.get("position", 0) + 1, field_name)

            self.order_fields(self.field_order)

字符串
这段代码允许我相应地呈现字段。如果客户选择显示,例如"es"(西班牙语),可翻译字段("description_en")将被复制,我创建一个新字段("description_es")在field_order的右边位置。到目前为止,一切都很好。
但是当我发布表单时,视图中会发生这样的情况:

def form_valid(self, form):
        is_updating = True if form.instance.pk else False
        self.object = form.save()
        if is_updating:
            # Todo: print message
            pass
        breakpoint()
        """
        (Pdb++) form.is_valid()
        True
        (Pdb++) form.cleaned_data
        {'company': <Company: Test>, 'description_en': 'I have a library!', 'description_es': 'Tengo una biblioteca!'}
        (Pdb++) self.object = form.save()
        (Pdb++) self.object
        <Venue: TestVenue>
        (Pdb++) self.object.description_en
        'I have a library!'
        (Pdb++) self.object.description_es
        ''
        """
        return super().form_valid(form)


我不明白的是:为什么description_es值没有保存到对象中?

z6psavjg

z6psavjg1#

我设法找到了解决办法。
问题出在django.forms.models.BaseModelForm中,它通过在__init__()方法中使用object_data = model_to_dict(instance, opts.fields, opts.exclude),删除了Meta.fields中未定义的所有字段。
解决方案变为:

# ...
            for addable in to_add:
                for lang in addable.get("languages"):
                    field_name = f"{addable.get('name')}_{lang}"  # "description_es"
                    formfield = addable.get("formfield")
                    formfield.label = formfield.label.replace(f"[{default_lang}]", f"[{lang}]")
                    formfield.required = False
                    formfield.initial = getattr(self.instance, field_name, "")

                    self.fields[field_name] = formfield
                    self.field_order.insert(addable.get("position", 0) + 1, field_name)
                    # these lines made the difference
                    if field_name not in self._meta.fields:
                        self._meta.fields = self._meta.fields + (field_name,)

            self.order_fields(self.field_order)

字符串

相关问题