Django 自定义 ModelForm 元类,"object has no attribute '_meta'"
Django custom ModelForm metaclass, "object has no attribute '_meta'"
我正在尝试创建自定义 Django ModelForm 元数据class,这将允许对从源模型继承的表单字段进行一些额外的自定义,例如:
- 将选择限制为特定模型字段的所有可用子集
- 定义只读和必需的表单字段
- 设置字段的初始值
我这样做是因为我需要为单个模型使用几个不同的 ModelForm,每个模型都有上述选项的变体。这是我的元class:
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 class,它将成为实际 ModelForm 的父 class:
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' object has no attribute '_meta'
我做错了什么?具有多级继承的 metclass 链越来越混乱。感谢任何帮助
干杯
_meta
属性由 __new__
中的 ModelFormMetaclass
设置。问题是你没有在子 class 中正确调用 super()
,因此 ModelFormMetaclass
中没有调用 __new__
,因此 _meta
未设置。
对 super()
的调用应将当前 class 作为其第一个参数,因此应为:
new_class = super(models.CustomModelFormMetaclass, mcs).__new__(mcs, name, bases, attrs)
我正在尝试创建自定义 Django ModelForm 元数据class,这将允许对从源模型继承的表单字段进行一些额外的自定义,例如:
- 将选择限制为特定模型字段的所有可用子集
- 定义只读和必需的表单字段
- 设置字段的初始值
我这样做是因为我需要为单个模型使用几个不同的 ModelForm,每个模型都有上述选项的变体。这是我的元class:
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 class,它将成为实际 ModelForm 的父 class:
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' object has no attribute '_meta'
我做错了什么?具有多级继承的 metclass 链越来越混乱。感谢任何帮助
干杯
_meta
属性由 __new__
中的 ModelFormMetaclass
设置。问题是你没有在子 class 中正确调用 super()
,因此 ModelFormMetaclass
中没有调用 __new__
,因此 _meta
未设置。
对 super()
的调用应将当前 class 作为其第一个参数,因此应为:
new_class = super(models.CustomModelFormMetaclass, mcs).__new__(mcs, name, bases, attrs)