Django问题在ModelForms中继承formfield_callback [英] Django Problem inheriting formfield_callback in ModelForms
问题描述
我刚刚使用Django几个星期,所以我可能会遇到这种各种错误,但是:
我有一个基本的ModelForm我把一些样板的东西放在尽可能地保持DRY的状态,我所有的实际ModelForms只是将这个基本形式的子类化。这对于 error_css_class ='error'
和 required_css_class ='required'
但 formfield_callback非常有用= add_css_classes
不像我预期的那样工作。
forms.py
#snippet我发现
def add_css_classes(f,** kwargs):
field = f.formfield(** kwargs)
如果field和'class'不在field.widget.attrs中:
field.widget。 attrs ['class'] ='%s'%field .__ class __.__ name __。lower()
return field
class BaseForm(forms.ModelForm):
formfield_callback = add_css_classes #不工作
error_css_class ='error'
required_css_class ='required'
class Meta:
pass
class TimeLogForm(BaseForm) :
#我想要下一行在父类
#formfield_callback = add_css_classes
class Meta(BaseForm.Meta):
model = TimeLog
最终目标是在一个类型为datefield / timefield / datetimefield的表单上拍摄一些jquery datetime选择器。我希望应用程序中的所有日期时间字段使用相同的小部件,所以我选择这样做,而不是明确地为每个模型中的每个字段。在每个表单类中添加一个额外的行不是一个很大的交易,但它只是告诉我,我无法弄清楚。在django来源中挖掘出来,这可能是在做一些我不明白的事情:
django.forms.models
pre>
class ModelFormMetaclass(type):
def __new __(cls,name,bases,attrs):
formfield_callback = attrs.pop('formfield_callback',None)
但我不知道如何 __ init __
和 __ new __
都是混合的。在BaseForm中,我尝试覆盖 __ init __
并在调用super之前和之后设置formfield_callback,但我猜想它需要在args或kwargs中的某个地方。
__ new__在对象构造之前被调用。实际上,这是一个返回新构造对象的实例的工厂方法。
所以在ModelFormMetaclass中有3个关键行:
formfield_callback = attrs.pop('formfield_callback',无)#1
fields = fields_for_model (opts.model,opts.fields,
opts.exclude,opts.widgets,formfield_callback)#2
new_class.base_fields = fields#3
在课堂中,我们将base_fields附加到我们的表单。
现在我们来看看到 ModelForm类:
类ModelForm(BaseModelForm):
__metaclass__ = ModelFormMetaclass
这意味着当我们创建一个ModelForm实例来改变ModelFormMetaclass .__ new __(...)未来实例的结构。而在_ em> ModelFormMetaclass 中的__new__( def __new __(cls,name,bases,attrs))的attrs是所有属性 ModelForm类
所以决定是为我们的案例创建新的InheritedFormMetaclass(继承自Model EmormMetaclass )。不要忘记在 InheritedFormMetaclass 中调用父级的 新 。然后创建我们的 BaseForm类,并说:
__ metaclass__ = InheritedFormMetaclass
在__new __(...)中执行 InheritedFormMetaclass ,我们可以做所有我们想要的。
如果我的答案不够详细,请在意见的帮助下告诉我。
I've only been using Django for a couple of weeks now, so I may be approaching this all kinds of wrong, but:
I have a base ModelForm that I put some boilerplate stuff in to keep things as DRY as possible, and all of my actual ModelForms just subclass that base form. This is working great for error_css_class = 'error'
and required_css_class = 'required'
but formfield_callback = add_css_classes
isn't working like I would expect it to.
forms.py
# snippet I found
def add_css_classes(f, **kwargs):
field = f.formfield(**kwargs)
if field and 'class' not in field.widget.attrs:
field.widget.attrs['class'] = '%s' % field.__class__.__name__.lower()
return field
class BaseForm(forms.ModelForm):
formfield_callback = add_css_classes # not working
error_css_class = 'error'
required_css_class = 'required'
class Meta:
pass
class TimeLogForm(BaseForm):
# I want the next line to be in the parent class
# formfield_callback = add_css_classes
class Meta(BaseForm.Meta):
model = TimeLog
The end goal is to slap some jquery datetime pickers on forms with a class of datefield/timefield/datetimefield. I want all of the date time fields within the app to use the same widget, so I opted to do it this way than explicitly doing it for each field in every model. Adding an extra line to each form class isn't that big of a deal, but it just bugged me that I couldn't figure it out. Digging around in the django source showed this is probably doing something I'm not understanding:
django.forms.models
class ModelFormMetaclass(type):
def __new__(cls, name, bases, attrs):
formfield_callback = attrs.pop('formfield_callback', None)
But I don't know how __init__
and __new__
are all intermangled. In BaseForm I tried overriding __init__
and setting formfield_callback before and after the call to super, but I'm guessing it needs to be somewhere in args or kwargs.
__new__ is called before object construction. Actually this is a factory method that returns the instance of a newly constructed object.
So there there are 3 key lines in ModelFormMetaclass:
formfield_callback = attrs.pop('formfield_callback', None) #1
fields = fields_for_model(opts.model, opts.fields,
opts.exclude, opts.widgets, formfield_callback) #2
new_class.base_fields = fields #3
In the class we attach base_fields to our form.
Now let's look to ModelForm class:
class ModelForm(BaseModelForm):
__metaclass__ = ModelFormMetaclass
This means that ModelFormMetaclass.__new__(...) will be called when we create a ModelForm instance to change the structure of the future instance. And attrs of __new__ (def __new__(cls, name, bases, attrs)) in ModelFormMetaclass is a dict of all attributes of ModelForm class.
So decision is to create new InheritedFormMetaclass for our case (inheriting it from ModelFormMetaclass). Don't forget to call new of the parent in InheritedFormMetaclass. Then create our BaseForm class and say:
__metaclass__ = InheritedFormMetaclass
In __new__(...) implementation of InheritedFormMetaclass we could do all we want.
If my answer is not detailed enough please let me know with help of comments.
这篇关于Django问题在ModelForms中继承formfield_callback的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!