3

I read many links to this problem:

How to save a django model with a manyToMany Through relationship, AND regular manyToMany relationships

How to save a django model with a manyToMany Through relationship, AND regular manyToMany relationships

django manytomany through

Include the DOC: https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

But can't save my M2M with through intermediary class.

My models:

class Promotor(PessoaFisica):
    user = models.OneToOneField(User, blank=True, null=True)    


class Setor(models.Model):
    nome = models.CharField(max_length=255)
    promotores = models.ManyToManyField(Promotor, through='Membro', blank=True, null=True)     

    class Meta:
        verbose_name_plural = 'setores'

    def __unicode__(self):
        return "%s" % (self.nome)

class Membro(models.Model):
    promotor = models.ForeignKey(Promotor)
    setor = models.ForeignKey(Setor)
    data_inclusao = models.DateField(auto_now=True)  

The save method:

def add_setor(request):
    form = SetorForm(request.POST or None)
    if form.is_valid():
        s = form.save()    
        setor = get_object_or_404(Setor, pk = s.id)    
        for promotor_id in request.POST.getlist('promotores'):
            membro = Membro.objects.create(promotor_id=promotor_id, setor_id=setor.id)          
            membro.save()         
        messages.add_message(request, messages.SUCCESS, 'Setor cadastrado com sucesso!')
        return HttpResponseRedirect('/project/setor/index/')
    return render_to_response('project/setor/form.html', locals(), context_instance=RequestContext(request))

The error is:

Cannot set values on a ManyToManyField which specifies an intermediary model.  Use setor.Membro's Manager instead.

If the save() method have commit "false", the "setor" does not have the "id" to put in Membro object. How to save setor with this through intermediary class? Thanks!

Community
  • 1
  • 1
LinuxMan
  • 427
  • 1
  • 7
  • 18
  • possible duplicate of [django Cannot set values on a ManyToManyField which specifies an intermediary model. Use Manager instead](http://stackoverflow.com/questions/3091328/django-cannot-set-values-on-a-manytomanyfield-which-specifies-an-intermediary-mo) – juliocesar May 26 '14 at 20:39

2 Answers2

4

You have promotores field in your form linked to the model so save() tries to save it to m2m field. You can save form with commit=False, then save object manually (it will not touch m2m) and then save m2m as you do now.

P.S. I guess you should use form.cleaned_data['promotores'] rather then request.POST. God knows what was actually POSTed from the client.

ilvar
  • 5,718
  • 1
  • 20
  • 17
  • Hi! The problem with commit=False is when i try to create a Membro object a error with id appears: Exception Type: IntegrityError Exception Value: (1048, "Column 'setor_id' cannot be null") This happens because form.save(commit=False) does not have a id. – LinuxMan Apr 20 '12 at 14:43
  • 1
    Because, as I said, you should save object manually after `form.save(commit=False)`. `Commit=False` is used here to only avoid saving m2m, so object should be saved manually. – ilvar Apr 20 '12 at 16:33
4

The solution for save a ManyToMany relation with a intermediary class (through):

def add_setor(request):
    form = SetorForm(request.POST or None)
    if form.is_valid():     
        setor = Setor.objects.create(nome=form.cleaned_data['nome'])
        for promotor_id in request.POST.getlist('promotores'):   
            m1 = Membro(promotor_id=promotor_id, setor=setor)
            m1.save()
        messages.add_message(request, messages.SUCCESS, 'Setor cadastrado com sucesso!')
        return HttpResponseRedirect('/project/setor/index/')
    return render_to_response('project/setor/form.html', locals(), context_instance=RequestContext(request))

I have not use the form directly, but extract the setor name of the form then create the object setor. Create the Membro object with the id's promotores in the form and the object setor, the last action is the save Membro object. Regards.

boatcoder
  • 17,525
  • 18
  • 114
  • 178
LinuxMan
  • 427
  • 1
  • 7
  • 18