如何指定 Django 表单中字段的顺序?
How do I specify order of fields in Django form?
我们正在使用 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()
returns ('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(...)
,但是如何定义来自模型的字段?我只想在字段列表的开头添加两个附加字段。
Is there a change in the implementation of the fields in forms
Django 2.2 和 3 之间的变化是声明字段的初始化方式:
- Django 2.2.12 https://github.com/django/django/blob/2.2.12/django/forms/forms.py#L39
- Django 3 https://github.com/django/django/blob/master/django/forms/forms.py#L36.
我想这是因为 Django 3 支持 Python 从版本 3.6 或更高版本 (https://docs.djangoproject.com/en/3.0/faq/install/) and since Python 3.6 dicts are insertion ordered ()。
我会将 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, '')
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()
可以使用
我在Django developers mailing list and I have been told not to manipulate the order of fields myself, but instead to use the supported API methods documented here问过。所以我更改了代码并使用 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)
请注意,我只对前两个字段进行排序。所有其他字段都保持默认顺序。我现在也不必以相反的顺序添加字段。
我们正在使用 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()
returns ('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(...)
,但是如何定义来自模型的字段?我只想在字段列表的开头添加两个附加字段。
Is there a change in the implementation of the fields in forms
Django 2.2 和 3 之间的变化是声明字段的初始化方式:
- Django 2.2.12 https://github.com/django/django/blob/2.2.12/django/forms/forms.py#L39
- Django 3 https://github.com/django/django/blob/master/django/forms/forms.py#L36.
我想这是因为 Django 3 支持 Python 从版本 3.6 或更高版本 (https://docs.djangoproject.com/en/3.0/faq/install/) and since Python 3.6 dicts are insertion ordered (
我会将 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, '')
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()
可以使用
我在Django developers mailing list and I have been told not to manipulate the order of fields myself, but instead to use the supported API methods documented here问过。所以我更改了代码并使用 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)
请注意,我只对前两个字段进行排序。所有其他字段都保持默认顺序。我现在也不必以相反的顺序添加字段。