Gareth D.
—You’ve seen related_name
defined in your Django models and you’re not sure what it does, or you want to use related_name
and you’re not sure how.
The related_name
field lets you access foreign keys defined in your Django models backwards, and override the default <model>_set
field that Django creates for convenient access to your linked models.
For example, usually if you want to find all books written by a specific author, you have to look in a Books
model and filter by author, using a query like Book.objects.filter(author=some_author)
. Sometimes it’s more convenient to start from the Author model and find all books by that author, using some_author.book_set.all()
The related_name
field lets you define what to call this backwards link. By default, Django already creates this for you using the name of the foreign key and the _set
suffix. Let’s use the following two models as an example.
from django.db import models class Author(models.Model): name = models.CharField(max_length=200) def __repr__(self): return self.name class Book(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE) title = models.CharField(max_length=200) def __repr__(self): return f"{self.title} by {self.author.name}"
Let’s say we have only two authors in our database: Alex Smith and Sam Jones. Alex has written two books and Sam has written one. In a Django shell, we could run:
>>> from booktracker.models import Book, Author >>> Author.objects.all() <QuerySet [Alex Smith, Sam Jones]> >>> Book.objects.all() <QuerySet [How Django Works by Alex Smith, How to Sell Django Books by Alex Smith, What Alex Got Wrong by Sam Jones]>
The traditional way to get all the books written by Alex would be to import both the book and the author models, do a query for the author of interest, and then pass in that author as a filter when querying for books. This could be done as follows.
>>> from booktracker.models import Book, Author >>> alex = Author.objects.get(name="Alex Smith") >>> alex_books = Book.objects.filter(author=alex) >>> alex_books <QuerySet [How Django Works by Alex Smith, How to Sell Django Books by Alex Smith]>
And if you’re used to writing SQL statements, this is probably intuitive. The book table has a foreign key link to the author table, so each book “knows” who its author is, but authors don’t “know” what books they wrote. If you’re a human, it’s probably not intuitive and you’d prefer to deal only with the Author object and get a list of books belonging to that author. With Django, you can do look-ups in reverse as follows.
>>> from booktracker.models import Author >>> alex = Author.objects.get(name="Alex Smith") >>> alex.book_set.all() <QuerySet [How Django Works by Alex Smith, How to Sell Django Books by Alex Smith]>
Which gets the same results using less code, and we don’t even have to import our Books model.
The book_set
is the automatic related_name
that Django assigned to our Author model when we created the Book model with a ForeignKey linking it to Author. If you want to use a different name, you can customize it by setting related_name
. For example, if you change the definition of the Book model to:
class Book(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books") title = models.CharField(max_length=200) def __repr__(self): return f"{self.title} by {self.author.name}"
Then you can get all the books for a specific author using alex.books.all()
instead of alex.book_set.all()
, which is more intuitive still (note that this is a database change, so you’ll need to run migrations again after making it in the models.py file).
>>> from booktracker.models import Author >>> alex = Author.objects.get(name="Alex Smith") >>> alex.books.all() <QuerySet [How Django Works by Alex Smith, How to Sell Django Books by Alex Smith]>
related_name
If you want to disable this backwards link completely (for example, to save a bit of space in the database index that Django needs to make this work), you can set related_name="+"
. After doing this, the book_set
relation will no longer exist.
>>> from booktracker.models import Author >>> alex = Author.objects.get(name="Alex Smith") >>> alex.book_set.all() Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'Author' object has no attribute 'book_set'
Tasty treats for web developers brought to you by Sentry. Get tips and tricks from Wes Bos and Scott Tolinski.
SEE EPISODESConsidered “not bad” by 4 million developers and more than 100,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.
Here’s a quick look at how Sentry handles your personal information (PII).
×We collect PII about people browsing our website, users of the Sentry service, prospective customers, and people who otherwise interact with us.
What if my PII is included in data sent to Sentry by a Sentry customer (e.g., someone using Sentry to monitor their app)? In this case you have to contact the Sentry customer (e.g., the maker of the app). We do not control the data that is sent to us through the Sentry service for the purposes of application monitoring.
Am I included?We may disclose your PII to the following type of recipients:
You may have the following rights related to your PII:
If you have any questions or concerns about your privacy at Sentry, please email us at compliance@sentry.io.
If you are a California resident, see our Supplemental notice.