modelchoicefield form example dependent chained python django drop-down-menu foreign-keys inline-formset

python - example - Guardar formset con menú desplegable Foreignkey: IntegrityError XXX_id puede no ser NULL



modelchoicefield django (1)

Estoy intentando tener un formset donde cada formulario (PropertySelector) tiene un menú desplegable (PropertySelector.property) mientras que cada elemento de ese menú es ForeignKey referencia a otro modelo (Property).

De alguna manera, cuando intento enviar y guardar el formset, obtengo:

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

¿Qué tiene de malo y cómo puedo evitarlo? Mi código completo está debajo. Gracias.

EDITAR: me parece un problema inline_formset (quizás MySQL también). Por favor, ayúdenme con la solución.

El proyecto se llama testproj y mi aplicación también se llama testproj.

Primero llenamos la Propiedad:

>>> 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 (plantilla):

{% 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 %}


El property_id no se guarda porque no lo incluye en su form.Meta . Deje los campos, y funciona:

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

Cambiaría el nombre de PropertySelForm a property_selectorform_factory , pero así soy yo. :)