Django问题在ModelForms中继承formfield_callback [英] Django Problem inheriting formfield_callback in ModelForms

查看:286
本文介绍了Django问题在ModelForms中继承formfield_callback的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆