Django - RelatedManager.set not removing models
In my opinion, one of django's biggest gotchas is using RelatedManager.set
with models that have non-nullable ForeignKey fields.
Models.py (with a one-to-many relationship and a non-nullable ForeignKey):
class Reporter(models.Model):
name = models.CharField(max_length=255)
class Article(models.Model):
title = models.CharField(max_length=255)
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
Guess how many articles are on the reporter after you do this?:
reporter = Reporter.objects.create(name="paul")
# add 2 articles to the reporter
article_1 = reporter.article_set.create(title="blah")
reporter.article_set.create(title="blah2")
# set only 1 article on the reporter
reporter.article_set.set([article_1])
I expected just one article to be on the reporter. Nope:
reporter.article_set.count()
2
How do the docs say it should work?
This method accepts a clear argument to control how to perform the operation. If False (the default), the elements missing from the new set are removed using remove() and only the new ones are added.
Well, crap, what's going on?
It turns out you need to read the docs for RelatedManager.remove
for a hint:
For ForeignKey objects, this method only exists if null=True.
So, it turns out that set()
is using remove()
and remove()
is only available on models with ForeignKeys that are null=True
. What does set()
do with things it needs to remove()
when remove()
isn't available? Nothing...