Reputation: 8618
Lots of questions cover saving instances before M2M relationships, however I have a problem achieving this when saving via a form with a _set
relationship, which does not appear to be covered in other answers.
I have two models with an M2M relationship:
class Author(models.Model):
name = models.CharField()
class Publisher(models.Model):
authors = models.ManyToManyField(Author)
When creating a new Author, I want to be able to set Publishers for that Author. Currently I handle this in the form:
class AuthorForm(forms.ModelForm):
publishers = forms.ModelMultipleChoiceField(queryset=Publisher.objects.all())
def __init__(self, *args, **kwargs):
super(AuthorForm, self).__init__(*args, **kwargs)
# If the form is used in a UpdateView, set the initial values
if self.instance.id:
self.fields['publishers'].initial = self.instance.publisher_set.all(
).values_list('id', flat=True)
def save(self, *args, **kwargs):
instance = super(AuthorForm, self).save(*args, **kwargs)
# Update the M2M relationship
instance.issuer_set.set(self.cleaned_data['issuers'])
return instance
class Meta:
model = Author
fields = ['name', 'publishers']
This works fine when updating an existing Author. However, when I use it to create a new one I get:
<Author: Sample Author>
needs to have a value for field "id" before this many-to-many relationship can be used.
I understand this is because the instance needs to be saved first, however in def save()
I am doing this (instance = super(AuthorForm, self).save(*args, **kwargs)
).
Where am I going wrong?
Upvotes: 0
Views: 522
Reputation: 51988
calling super
does not guarantee that it will create an instance. Because, form's save(...)
method has a argument called commit
, if the method calling the save
is passing commit=False
(for example: form.save(commit=False)
), then it will not save the instance. So you need to explicitly save it. Like this:
instance = super(AuthorForm, self).save(commit=True)
Upvotes: 1