Sentry Answers>Django>

What is related_name used for?

What is related_name used for?

Gareth D.

The problem

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 solution

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.

Click to Copy
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:

Click to Copy
>>> 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.

Click to Copy
>>> 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.

Click to Copy
>>> 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:

Click to Copy
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).

Click to Copy
>>> 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]>

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.

Click to Copy
>>> 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'
  • Syntax.fmListen to the Syntax Podcast
  • Community SeriesIdentify, Trace, and Fix Endpoint Regression Issues
  • ResourcesBackend Error Monitoring 101
  • Syntax.fm logo
    Listen to the Syntax Podcast

    Tasty treats for web developers brought to you by Sentry. Get tips and tricks from Wes Bos and Scott Tolinski.

    SEE EPISODES

Considered “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.

© 2024 • Sentry is a registered Trademark of Functional Software, Inc.