【问题标题】:Saving formset with drop-down-menu Foreignkey: IntegrityError XXX_id may not be NULL使用下拉菜单外键保存表单集:IntegrityError XXX_id 可能不是 NULL
【发布时间】:2014-03-08 20:49:26
【问题描述】:

我正在尝试创建一个表单集,其中每个表单 (PropertySelector) 都有一个下拉菜单 (PropertySelector.property),而该菜单的每个项目都是对另一个模型 (Property) 的 ForeignKey 引用。

当我尝试提交并保存我得到的表单集时:

Exception Type:     IntegrityError
Exception Value:    testproj_propertyselector.property_id may not be NULL

它有什么问题,我该如何解决?我的整个代码如下。谢谢。

编辑:对我来说,它看起来像 inline_formset 问题(也许 MySQL 也是)。请帮我解决问题。

该项目称为 testproj,我的应用程序也称为 testproj。

首先我们填充属性:

>>> from testproj.models import Property
>>> p = Property(name='prop1', basic=True)
>>> p.save() 
>>> p = Property(name='prop2', basic=True)
>>> p.save()

models.py

from django.db import models

class PropertySet(models.Model):
    name = models.CharField(max_length=50)

class Property(models.Model):
    name = models.CharField(max_length=50)
    basic = models.BooleanField()

    def __unicode__(self):
        return u'%s' % (self.name)

class PropertySelector(models.Model):
    property_set = models.ForeignKey(PropertySet)
    title = models.CharField(max_length=50)
    property = models.ForeignKey(Property)

forms.py

from django.forms import ModelForm, TextInput, Select, ModelChoiceField
from django.db.models import Q
from testproj.models import Property, PropertySet, PropertySelector

class PropertySetForm(ModelForm):
    class Meta:
        model = PropertySet

def PropertySelForm():
    PropertyQueryset = Property.objects.filter(Q(basic=True))

    class PropertySelectorForm(ModelForm):
        property = ModelChoiceField(
            queryset=PropertyQueryset,
            widget=Select(attrs={'class': 'property'})
        )

        def __init__(self, *args, **kwargs): 
            super(ModelForm, self).__init__(*args, **kwargs)
            self.css_class = "prop_sel"

        class Meta:
            model = PropertySelector
            fields = ("property_set", "title")
            widgets = {"title" : TextInput(attrs={"class" : "title"})}

    return PropertySelectorForm

views.py

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.forms.models import inlineformset_factory

from testproj.models import PropertySet, PropertySelector
from testproj.forms import PropertySetForm, PropertySelForm, PropertySelForm

def index(request):

    property_selector_form = PropertySelForm()
    PropertySelectorFormSet = inlineformset_factory(PropertySet, PropertySelector, form=property_selector_form)

    if request.method == "POST":

        property_set_form = PropertySetForm(request.POST)

        if property_set_form.is_valid():            
            saved_property_set = property_set_form.save()

            prop_sel_formset = PropertySelectorFormSet(request.POST, instance=saved_property_set)

            if prop_sel_formset.is_valid():
                prop_sel_formset.save()

        else:

            property_set_form = PropertySetForm()

            prop_sel_formset = PropertySelectorFormSet()    

        return render_to_response(
            "testproj/index.html",
            {
                "property_set_form": property_set_form,
                "prop_sel_formset": prop_sel_formset
            },
            context_instance=RequestContext(request)
        )

index.html(模板):

{% block content %}

<head>

</head>

<body>

<form method="post" action=""> {% csrf_token %}

    {{ property_set_form.as_p }}

    {{ prop_sel_formset.management_form }}

    {% for form in prop_sel_formset %}
        {{ form }}

    {% endfor %}

    <input type="submit" value="Submit">    
</form>

</body>
{% endblock %}

【问题讨论】:

  • 看起来您正在使用中间模型建模多对多关系。为此,您可以使用 ManyToManyFieldthrough 参数。
  • 我不认为它是ManyToMany,至少我不是这样设计的。只是PropertySelect有两个foreignKey:PropertySet和Property,所​​以有两个ManyToOne关系。
  • 我认为问题在于 inline_formset 只接受一个 ForeignKey 作为参数,我不知道如何绕过它。
  • 无论如何,我修改了代码以使用带有 through 参数的 ManyToManyField,我得到了相同的错误消息。正如我上面提到的,对我来说它看起来像 inline_formset 问题(也许 MySQL 也是)?
  • 嗯,我在管理员中使用带有内联的through,它们工作正常。

标签: python django drop-down-menu foreign-keys inline-formset


【解决方案1】:

property_id 未保存,因为您未将其包含在您的 form.Meta 中。离开字段,它就可以工作了:

def PropertySelForm():
    PropertyQueryset = Property.objects.filter(Q(basic=True))

    class PropertySelectorForm(ModelForm):
        property = ModelChoiceField(
            queryset=PropertyQueryset,
            widget=Select(attrs={'class': 'property'})
        )

        def __init__(self, *args, **kwargs): 
            super(ModelForm, self).__init__(*args, **kwargs)
            self.css_class = "prop_sel"

        class Meta:
            model = PropertySelector
            #fields = ("property_set", "title")
            widgets = {"title" : TextInput(attrs={"class" : "title"})}

    return PropertySelectorForm

我会将 PropertySelForm 重命名为 property_selectorform_factory,但那是 只有我。 :)

【讨论】:

  • PropertySelForm() 是一个返回 ModelForm 的函数。这里没问题。
  • 我明白了。我被骆驼案蒙蔽了双眼。猜猜我的 pep8 过量了。
  • 如果您在PropertySelForm 中所做的操作应该适用于所有PropertySelectors,您可以使用property = models.ForeignKey(Property, limit_choices_to=Q(basic=True)) 在您的模型上设置它
  • 在真正的应用程序中,它会涉及更多,因为我将使用 Q(basic=True) | Q(用户=用户)
  • 啊,user 在模型加载时当然是未知的。
猜你喜欢
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-25
相关资源
最近更新 更多