【问题标题】:Override the initialization of a ChoiceField in django在 django 中覆盖 ChoiceField 的初始化
【发布时间】:2013-08-30 11:36:41
【问题描述】:

我正在尝试在 django 中初始化一个包含 ChoiceField 的表单。我有以下代码:

# in file models.py
class Locality(models.Model):
    locality = models.CharField(primary_key=True, unique=True, max_length=36)
    def __unicode__(self):
        return self.locality

# in file forms.py
class RegisterForm(forms.Form): 
    def __init__(self, *args, **kwargs):
        self.username = forms.CharField(required=True)
        self.email = forms.EmailField(required=True)
        self.locality = forms.ChoiceField(widget=forms.Select())
        self.fields['locality'].choices = [l.locality for l in Locality.objects.all()]

但是在外壳上,一旦我尝试实例化:

r = RegisterForm(username="toto", email="a@b.com")

我收到'RegisterForm' object has no attribute 'fields' error。这是因为物体还没有形成吗?如何访问ChoiceField

任何帮助表示赞赏。

【问题讨论】:

    标签: python django django-forms


    【解决方案1】:

    您没有以良好的方式使用Form 对象。 fields 属性是初始化 by the __init__ method of BaseForm (see the source code)forms.Form 的父类),但是你重新定义了它,所以你破坏了这个过程。

    因此,您应该在 __init__ 方法中调用父级 __init__,如下所示:

    class RegisterForm(forms.Form): 
        username = forms.CharField(required=True)
        email = forms.EmailField(required=True)
        locality = forms.ChoiceField(widget=forms.Select())
    
        def __init__(self, *args, **kwargs):
             super(forms.Form, self).__init__(*args, **kwargs)
             self.fields['locality'].choices = [(l.id, l.locality) for l in Locality.objects.all()]
    

    我已将每个*Field 声明移到__init__ 之外,因为这是常用方式。它的问题与上一个问题非常相似:Override defaults attributes of a Django form

    【讨论】:

    • 更新,就在我看到你的评论之前
    • self.fields['locality'].choices = [l.locality for l in Locality.objects.all()] 是错误的。你必须使用self.fields['locality'].choices = [(l.id,l.locality) for l in Locality.objects.all()] 我的意思是选择必须是格式[(..,..),(..,..),..]
    • 你说得对,我只是复制作者的行,没有检查列表理解,但想法就在这里;)(再次更新)
    • 您好 Maxime,感谢您的回答,这听起来合乎逻辑。但是 forms.Form.__init__ 不是一个可识别的符号,并且在 BaseForm 中使用 init
    • 几分钟前我已经用super 语法改变了我的答案;)
    【解决方案2】:

    尝试:

    def __init__(self, *args, **kwargs):
         super(forms.Form, self).__init__(*args, **kwargs)
         self.fields['locality'].choices = [(l.id, l.locality) for l in Locality.objects.all()]
    

    【讨论】:

    • 该列表将在表单声明时创建。如果他在服务器启动后在 Locality 中添加一个新值,这个新值将不会出现在选择列表中。相反,每次实例化新表单时都会调用 __init__ 函数。
    • @MaximeLorant 选择的格式必须为[(..,..),(..,..),..]
    • @MaximeLorant 我在我的所有项目中都使用这种方法并且效果很好。
    • 即使修改/删除Locality中的数据?也许你是对的,通过快速查看课程,我看到发生了一些深拷贝......有一些疑问,但好吧,我删除了我的反对票:)
    • @MaximeLorant 是的,你是对的。我不是那个意思。我谈到了[(..,..)..
    猜你喜欢
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2012-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多