【问题标题】:How do I specify order of fields in Django form?如何在 Django 表单中指定字段的顺序?
【发布时间】:2020-07-23 05:05:44
【问题描述】:

我们正在使用 Django 2.2,我想升级到 Django 3.0。我们有一个向表单添加字段的 mixin(写于 2017 年):

class LocalizedFirstLastNameMixin(object):
    def __init__(self, *args, **kwargs):
        self.language_code = kwargs.pop('language_code', 'en')
        super().__init__(*args, **kwargs)
        for loc_field in reversed(self.get_localized_fields()):
            self.fields[loc_field] = User._meta.get_field(loc_field).formfield()
            self.fields[loc_field].required = True
            self.fields.move_to_end(loc_field, last=False)
            self.initial[loc_field] = getattr(self.instance, loc_field, '')

self.get_localized_fields() 以英语返回 ('first_name_en', 'last_name_en')(按此顺序),或者本地化为我们当前使用的语言。

这个mixin被用作继承自ModelForm的表单的基类之一:

class RegistrationForm(AddAttributesToFieldsMixin, CleanEmailMixin, CleanNewPasswordMixin, CleanDateOfBirthMixin, LocalizedFirstLastNameMixin, forms.ModelForm):
    ....

class ProfileForm(AddAttributesToFieldsMixin, CleanDateOfBirthMixin, LocalizedFirstLastNameMixin, forms.ModelForm):
    ....

它适用于最高 2.2 的 Django 版本。但是当我升级到 3.0 时,我收到以下错误消息:

AttributeError: 'dict' object has no attribute 'move_to_end'

这个函数的信息:

Move an existing element to the end (or beginning if last==False).

它属于OrderedDict

所以我想我们希望这些字段位于表单字段的开头。

Django 3.0 中表单中字段的实现是否有变化,如何指定字段的顺序?如果我更改它,它是否可以在以前的版本(例如 Django 2.2)中运行?

我检查了Django 3.0 release notes 以及从 3.0.1 到 3.0.5 的版本,但我没有找到任何有关此问题的文档。

更新:我发现我可以调用self.order_fields(...),但是如何定义来自模型的字段?我只想在字段列表的开头添加两个额外的字段。

【问题讨论】:

    标签: python django django-forms modelform django-3.0


    【解决方案1】:

    我在Django developers mailing list 中询问过,有人告诉我不要自己操纵字段的顺序,而是使用记录在here 中的受支持的API 方法。所以我改了代码,改用self.order_fields

    class LocalizedFirstLastNameMixin(object):
        def __init__(self, *args, **kwargs):
            self.language_code = kwargs.pop('language_code', 'en')
            super().__init__(*args, **kwargs)
            localized_fields = self.get_localized_fields()
            for loc_field in localized_fields:
                self.fields[loc_field] = User._meta.get_field(loc_field).formfield()
                self.fields[loc_field].required = True
                self.initial[loc_field] = getattr(self.instance, loc_field, '')
            self.order_fields(field_order=localized_fields)
    

    请注意,我只对前两个字段进行排序。所有其他字段都保持默认顺序。我现在也不必以相反的顺序添加字段。

    【讨论】:

      【解决方案2】:

      表单中字段的实现是否有变化

      Django 2.2 和 3 之间的变化是声明字段的初始化方式:

      我猜这是因为 Django 3 支持 Python 3.6 或更高版本 (https://docs.djangoproject.com/en/3.0/faq/install/) 并且因为 Python 3.6 dicts 是插入顺序的 (Are dictionaries ordered in Python 3.6+?)。


      我会将self.fields 转换为OrderedDict(基本上会回到以前的2.2 版本)以再次启用self.fields.move_to_end

      from collections import OrderedDict
      
      
      class LocalizedFirstLastNameMixin(object):
          def __init__(self, *args, **kwargs):
              self.language_code = kwargs.pop('language_code', 'en')
              super().__init__(*args, **kwargs)
              self.fields = OrderedDict(self.fields)
              for loc_field in reversed(self.get_localized_fields()):
                  self.fields[loc_field] = User._meta.get_field(loc_field).formfield()
                  self.fields[loc_field].required = True
                  self.fields.move_to_end(loc_field, last=False)
                  self.initial[loc_field] = getattr(self.instance, loc_field, '')
      

      【讨论】:

      • 感谢您的想法。我在__init__ 方法中的super()... 之后定义了self.fields = OrderedDict(self.fields)(我认为它不应该在for 循环中),并且它有效。但是改self.fields的定义不会有问题吗?
      • 我不这么认为,因为OrderedDict 是 dict (docs.python.org/3.8/library/…) 的子类。
      • 我改变了主意,我不能接受这个答案作为接受的答案。请看我的回答。
      【解决方案3】:

      OrderedDict 来自标准库。

      from collections import OrderedDict
      

      实例有.move_to_end(),它只是说你dict 对象没有.move_to_end(),这意味着你使用的是普通的字典。像这样将其投射到OrderedDict

      x = { "key" : "value"}
      y = OrderedDict(x)
      # OrderedDict([('key', 'value')])
      

      现在.move_to_end() 可以工作了

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-08
        • 2017-04-23
        • 2015-02-17
        • 2010-09-25
        • 2010-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多