问题
I am trying to have a formset where each form (PropertySelector) has a drop-down menu (PropertySelector.property) whereas each item of that menu is ForeignKey reference to another model (Property).
Somehow when I am trying to submit and save the formset I am getting:
Exception Type: IntegrityError
Exception Value: testproj_propertyselector.property_id may not be NULL
What is wrong with it and how can I get around it? My entire code is below. Thanks.
EDIT: it looks like inline_formset problem to me (maybe MySQL also). Please, help me with workaround.
The project is called testproj and my app is called testproj too.
First we populate Property:
>>> 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 (template):
{% 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 %}
回答1:
The property_id
isn't saved because you don't include it in your form.Meta
. Leave away the fields, and it works:
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
I'd rename PropertySelForm
to property_selectorform_factory
, but that's
just me. :)
来源:https://stackoverflow.com/questions/22274895/saving-formset-with-drop-down-menu-foreignkey-integrityerror-xxx-id-may-not-be