Поля и base_fields - Django

При создании плоской страницы я хочу, чтобы пользователь выбирал шаблон из предопределенного списка. Чтобы сохранить модель Flatpage нетронутой, я предпочитаю ChoiceField над ModelChoiceField (последний предоставляет PK шаблона, но мне нужно имя для поля template_name):

class NewFlatpageForm(FlatpageForm):

    template_name = forms.ChoiceField(choices = [])
    def __init__(self, *args, **kwargs):
        self.base_fields['template_name'].choices = ProjectTemplate.objects.values_list('path', 'name')
        super(NewFlatpageForm, self).__init__(*args, **kwargs)

Я переопределяю __init__ или Django заполняет варианты при запуске сервера и не обновляет список.

У меня нет никакого администрирования, но я делал подобные вещи, используя атрибут fields, когда не использовал admin. Однако в этом случае я получил исключение, говорящее, что fields не является атрибутом формы. __dict__ показал мне атрибут base_fields, и его использование работает. Итак, зачем использовать base_fields здесь, и почему fields нет, и, наконец, я делаю что-то взломанное?

Ответ 1

fields не существует до после, который вы вызывали super. Поэтому просто поменяйте порядок строк, чтобы super появился первым.

Ответ 2

Урок по собственному опыту: изменение базовых полей означает, что ваши модификации придерживаются "навсегда" (до выхода python). В вашем случае это, вероятно, не проблема, поскольку вы всегда используете одно и то же имя поля, и вы заменяете его значения назначением из ProjectTemplate...

В моем случае я хотел получить совершенно разные поля на основе параметров в конструкторе. Поскольку имена полей обычно отличались друг от друга, каждый раз, когда я создавал форму, я добавлял новые поля, но не удалял их из последнего раза.

Вызывая супер ранний (как указано здесь), а затем делая мои динамические изменения в self.fields вместо self.basefields, я смог устранить проблему постоянно растущего списка полей. Теперь это имеет прекрасный смысл, но я не был знаком со всеми деталями синтаксиса и взломал вместо того, чтобы сначала понять его.

Ответ 3

В дополнение к Джо Гермушке. Если вам действительно нужно изменить форму на основе запроса, вы можете использовать глубокую копию, чтобы убедиться, что ничто не изменяется по ссылке:

def get_form(self, request, obj=None, **kwargs):
    form = super(ResourceAdmin, self).get_form(request, obj, **kwargs)
    form = copy.deepcopy(form)

    if obj:
        form.base_fields['email'] = EmailField(initial=obj.user.email)
    if not request.user.is_superuser:
        form.base_fields['user'].widget = HiddenInput(attrs={'class': 'hide_form_row'})

    return form