Как указать порядок полей в форме Django? - PullRequest
0 голосов
/ 10 апреля 2020

Мы используем Django 2.2, и я хочу обновить до Django 3.0. У нас есть миксин (написанный в 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') (в этом порядке) на английском языке sh, или то же самое, локализованное на текущий язык мы используем.

Этот миксин используется как один из базовых классов для форм, которые наследуются от ModelForm:

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

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

. Он работает с Django версиями до 2.2. Но когда я обновляюсь до 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, примечания к выпуску , а также выпуски с 3.0.1 до 3.0. 5, и я не нашел документации по этой проблеме.

Обновление: Я обнаружил, что могу звонить self.order_fields(...), но как мне определить поля, полученные из моделей? ? Я хочу добавить только два дополнительных поля в начале списка полей.

Ответы [ 3 ]

1 голос
/ 11 апреля 2020

Я спросил в списке рассылки Django для разработчиков , и мне сказали, что я не должен сам манипулировать порядком полей, а вместо этого использую поддерживаемые методы 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)

Обратите внимание, что я заказываю только первые два поля. Все остальные поля хранятся в порядке по умолчанию. Мне также не нужно добавлять поля в обратном порядке.

1 голос
/ 10 апреля 2020

Есть ли изменения в реализации полей в формах

Что изменилось между Django 2.2 и 3, так это то, как объявленные поля инициализируются:

Полагаю, это потому что Django 3 поддерживает Python от версии 3.6 или новее (https://docs.djangoproject.com/en/3.0/faq/install/), а поскольку Python 3.6, дикты имеют порядок вставки ( Упорядочены ли словари в 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, '')
0 голосов
/ 10 апреля 2020

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() будет работать

...