I have a M2M relationship between two Models which uses an intermediate model. For the sake of discussion, let's use the example from the manual:
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
I'd like to make use of Django's Class-based views, to avoid writing CRUD-handling views. However, if I try to use the default CreateView, it doesn't work:
class GroupCreate(CreateView):
model=Group
This renders a form with all of the fields on the Group object, and gives a multi-select box for the members field, which would be correct for a simple M2M relationship. However, there is no way to specify the date_joined or invite_reason, and submitting the form gives the following AttributeError:
"Cannot set values on a ManyToManyField which specifies an intermediary model. Use Membership's Manager instead."
Is there a neat way to override part of the generic CreateView, or compose my own custom view to do this with mixins? It feels like this should be part of the framework, as the Admin interface atomatically handles M2M relationships with intermediates using inlines.
'For reference, I didn't end up using a class-based view, instead I did something like this:
This may be a starting point for a Class-based implementation, but it's simple enough that it's not been worth my while to try to shoehorn this into the Class-based paradigm.
Just one comment, when using CBV you need to save the form with commit=True, so the group is created and an id is given that can be used to create the memberships. Otherwise, with commit=False, the group object has no id yet and an error is risen.
I was facing pretty the same problem just a few days ago. Django has problems to process intermediary m2m relationships.
This is the solutions what I have found useful:
Then alter the save method of defined form - GroupCreateForm. Save is responsible for making changes permanent to DB. I wasn't able to make this work just through ORM, so I've used raw SQL too:
Note:I've changed the model a little bit, as you can see (i have own unique IntegerField for primary key, not using serial. That's how it got into
get_object_or_404
You must extend
CreateView
:and override the
form_valid()
:As the documentation says, you must create new
membership
s for each relation betweengroup
andperson
.I saw the
form_valid
override here: Using class-based UpdateView on a m-t-m with an intermediary model