guardar datos del formulario con un campo de clave externa personalizado en django

I have the following Model classes:

class ContactPerson(models.Model):            
    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name

class Appartment(models.Model):
    contact_person = models.ForeignKey(ContactPerson)

Problema: In template file I want a user to fill contact person's name, so I overwrite contact_person field as follows:

class AppartmentSellForm(ModelForm):
    contact_person = forms.CharField(max_length=30)

    class Meta:
        model = Appartment

In my view function I am doing the following to save data from a form submitted:

def appartment_submit(request):
    if request.method == "POST":
        form = AppartmentSellForm(request.POST)
        if form.is_valid():
            appartment = form.save(commit=False) # ERROR HERE
            cp = models.ContactPerson(name=form.cleaned_data['contact_person'])
            appartment.contact_person = cp
            appartment.save()
            form.save();
            return HttpResponseRedirect('/sell/')
    else:
        form = AppartmentSellForm()
    return render_to_response('sell_appartment_form.html', {'form' : form})

Mensaje de error:

#ValueError at /sell/sell_appartment/appartment_submit/

Cannot assign "u'blabla'": "Appartment.contact_person" must be a "ContactPerson" instance.**

I am using SQLite, and django version 1.1.1

Pregunta: ¿Cómo resolver este problema?

preguntado el 28 de agosto de 11 a las 03:08

That's a rather old version of Django, is there a reason you're not using 1.3? -

Updating might, after fixing all errors and deprecation warnings you would get, ease your progress, it's really better. More on topic (with dusty Django skills), if you print the cp variable, do you get what you'd expect? -

@Jasper Kennis, the code fails before cp. But, yeah, if I comment out line above it, and print it, it is what I expect. Well, I am upgrading my django version... -

Hm, can you alter the values contained in form that are trying to be saved? In that case you should move the line where you define cp up, and alter forms value before you run save() on it. -

2 Respuestas

I think the code that you are putting in your view would be better suited to the ModelForm's validation.

Override the model form's clean_contact_person method and add the code there so that it a) checks that the name is valid and if so, b) sets the form field's value to the actual ContactPerson instance.

Something like: (off the top of my head)

class AppartmentSellForm(ModelForm):
    contact_person = forms.CharField(max_length=30)

    class Meta:
        model = Appartment

    def clean_contact_person(self):
        name = self.cleaned_data['contact_person']
        # check the name if you need to
        try:
            # maybe check if it already exists?
            person = models.ContactPerson.objects.get(name=name)
        except ContactPerson.DoesNotExist:
            person = models.ContactPerson(name=name)
            # you probably only want to save this when the form is saved (in the view)
        return person

Your view will may still need to use commit=False (since you will need to save the ContactPerson record). You can do this using the save_m2m método.

Hay más información sobre save_m2m in the ModelForm documentation and information about cleaning fields in la documentación de validación.

I hope that helps, good luck!

Respondido 28 ago 11, 20:08

Puede realizar una de las siguientes acciones:

  1. Trate de exclude los contact_person field, as mentioned in point 3 over here
  2. or you could just not override the field in your ModelForm and Django will render it as a ModelChoiceField, unless you actually want people to type out a name instead of having a dropdown list to choose from.

Respondido 28 ago 11, 12:08

si tu exclude it, it may not try to save the string as a ForeignKey did you try it? ... or you can try what @adamnfish suggested. - Roshan Mathews

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.