lembon
lembon

Reputation: 125

Django editing a Model object and a referenced object in one form

I think what I need to do is really the opposite of an inlineformset.

Say I have:

from django.db import models
class Type(models.Model):
    description = models.CharField(max_length=50)
    status = models.ForeignKey(Status)
    def __unicode__(self):
        return self.description

class ColorType(models.Model):
    type = models.ForeignKey(Type)
    color = models.ForeignKey('Color')
    status = models.ForeignKey(Status)
    def __unicode__(self):
        return u'%s %s' % (self.type, self.color)

class Color(models.Model):
    description = models.CharField(max_length=50)
    status = models.ForeignKey(Status)
    types = models.ManyToManyField(type, through=ColorType)
    def __unicode__(self):
        return self.description

class Chair(models.Model):
    description = models.CharField(max_length=50)
    status = models.ForeignKey(Status)
    colorType = models.ForeignKey(ColorType)

Now I need a form to edit a chair in which I enter Color and Type separatedly (Like showing a modelformset of ColorType). If the combination doesn't exist the application has to create the necessary instance of ColorType (and assigning it a desfault status) and assign it to the chair.

I think the whole situation is common, I should be missing something...

Upvotes: 2

Views: 145

Answers (2)

lembon
lembon

Reputation: 125

I will post my own solution. Finally I did the trick just by using the InlineFormsets.

In forms.py:

class ChairForm(forms.ModelForm):
    class Meta:
        model = Chair
        exclude = ('colorType')

class ColorTypeForm(forms.ModelForm):
    class Meta:
        model = ColorType
        exclude = ('status')

In views.py:

def ChairUpdate(request, chair_id):
    chair = get_object_or_404(Chair, pk=chair_id)

    form = ChairForm(instance=chair)
    ColorTypeInlineFormset = inlineformset_factory(ColorType, Chair, formset=ColorTypeForm)

    if request.method == 'POST':
        form = ChairForm(request.POST, instance=chair)
        if form.is_valid():
            chair = form.save(commit=False)
            colorTypeInlineFormset = ColorTypeInlineFormset(request.POST,)
            # colorTypeInlineFormset.is_valid()

            color = Color.objects.get(id=request.POST['color'])
            type = Type.objects.get(id=request.POST['type'])

            ct,created = ColorType.objects.get_or_create(color=color,type=type,defaults={'status':Status.objects.get(id=1)})
            chair.colorType = ct

            # marcaModeloInlineFormset.save(commit=False)
            arma.save()
            return HttpResponseRedirect(reverse('success_page'))

    colorTypeInlineFormset = ColorTypeInlineFormset(instance=chair.colorType)


    return render(request, "chair_form.html", {
        'chair': chair,
        'form': form,
        'colorType_formset': colorTypeInlineFormset,
        'action': "Update"
    })

Upvotes: 1

Nil
Nil

Reputation: 2390

I did my search and, sadly, it's not currently possible to have more than one model per form using only Django. This being said, you are not the only one who wanted to do that.

  • There's a SO answer here which make good suggestions.
  • If you still want to to it, you can roll your own using something like this, but a little different because this version accepts one form or the other, not both at once.
  • If you don't want to code it yourself, django-multiform is a Django library that offers a generic way to do what you want. Of course, you would need to change the save method to apply for your use-case (ColorType combination, etc.)

Upvotes: 1

Related Questions