Пользовательский метакласс ModelForm в Django, "объект не имеет атрибута _meta" - PullRequest
0 голосов
/ 13 ноября 2018

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

  • Ограничить выбор подмножеством всех доступных для определенного поля модели
  • Определить только для чтения и обязательные поля формы
  • Установить начальные значения для полей

Я делаю это, потому что мне нужно несколько разных ModelForms для одной Модели, каждая с вариациями вышеупомянутых опций. Вот мой метакласс:

class CustomModelFormMetaclass(models.ModelFormMetaclass):
"""
Custom ModelForm metaclass which adds extra configuration of fields inherited from Model
"""
def __new__(mcs, name, bases, attrs):
    new_class = super(models.ModelFormMetaclass, mcs).__new__(mcs, name, bases, attrs)
    # Set initial field values
    #initials = attrs.get('initial_values')
    for field_name, initial_value in new_class.initial_values.items():
        field = new_class.base_fields.get(field_name, None)
        if field and field.initial is None:
            field.initial = initial_value

    # Set refined choices
    #refined_choices = attrs.get('refined_choices')
    for field_name, refined_choices in new_class.refined_choices.items():
        set_field_choices(new_class, field_name,refined_choices)

    # Set disabled fields
    for field_name in new_class.read_only_fields:
        field = new_class.base_fields.get(field_name, None)
        if field:
            #field.disabled=True
            field.widget.attrs['readonly'] = True

    # Set required fields
    for field_name in new_class.required_fields:
        field = new_class.base_fields.get(field_name, None)
        if field:
            field.required=True

    # Set DateTime and Date help texts
    for field in new_class.base_fields.values():
        if field.help_text is None:
            if type(field).__name__ == 'DateTimeField':
                field.help_text = 'YYYY-MM-DD HH:MM:SS'
            elif type(field).__name__ == 'DateField':
                field.help_text = 'YYYY-MM-DD'

    return new_class

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

class CustomModelForm(forms.BaseModelForm, metaclass=CustomModelFormMetaclass):
method='post'
target=None
target_params={}

refined_choices={}

initial_values={}

read_only_fields=[]

required_fields= []

Один из таких примеров (в этом случае не используются мои пользовательские параметры):

class LBSListAdminForm(darwin_forms.CustomModelForm):
method = 'get'

class Meta:
    model = LBSListRequest
    exclude = ['start_time', 'site', 'process_id', 'user', 'duration', 'method', 'request_data', 'status', 'response']
    labels = {}
    help_texts = {}
    error_messages = {}
    widgets = {}

Однако я получаю эту ошибку:

Объект 'LBSListAdminForm' не имеет атрибута '_meta'

Что я здесь не так сделал? Цепочка metclass с несколькими уровнями наследования становится запутанной. Цени любую помощь

Приветствия

1 Ответ

0 голосов
/ 13 ноября 2018

Атрибут _meta устанавливается ModelFormMetaclass в __new__. Проблема в том, что вы неправильно вызвали super() в своем подклассе, и, таким образом, __new__ не был вызван в ModelFormMetaclass, и, следовательно, _meta не было установлено.

Вызов super() должен принять текущий класс в качестве первого аргумента, поэтому следует читать:

new_class = super(models.CustomModelFormMetaclass, mcs).__new__(mcs, name, bases, attrs)
...