In a Django model, what do related_name and related_query_name on a ForeignKey control, and when are you forced to set them?
answer
- the reverse side of the relation
- book_set versus book
- two keys to the same model
- abstract base classes and '+'
basics
~20 srelated_name names the reverse accessor on the target model (default book_set); related_query_name names the reverse lookup in filters (defaulting to related_name, else the model name). You must set them when two relations would produce clashing reverse names, including on abstract models.
solid answer
~40 sA `ForeignKey` on `Book` pointing at `Author` also adds a reverse side to `Author`. `related_name` names the reverse **accessor**, the manager you call on an author; without it Django uses `book_set`. `related_query_name` names the reverse **lookup** used in queryset filters from `Author`; it defaults to `related_name` if set, otherwise `Meta.default_related_name`, otherwise the lowercased model name, `book`. You are forced to set them when two relations from one model point at the same target, like `Book.author` and `Book.translator`, because the default names clash and the system checks report `fields.E304`/`fields.E305`. On an abstract base class you use `%(app_label)s` and `%(class)s` placeholders so each subclass gets its own name, and a name ending in `+` turns the reverse relation off.
code
python · 28 linesfrom django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
class Book(models.Model):
title = models.CharField(max_length=300)
author = models.ForeignKey(
Author,
on_delete=models.PROTECT,
related_name="authored_books",
related_query_name="authored_book",
)
translator = models.ForeignKey(
Author,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="translated_books",
)
# author.authored_books.all()
# Author.objects.filter(authored_book__title__icontains="django")
# author.translated_books.all()
# Author.objects.filter(translated_books__isnull=False)go deeper
Recall that a ForeignKey adds a reverse manager on the target, named book_set unless you set related_name.
Explain the accessor versus the query name, their defaults, and why two keys to one model or an abstract base force you to name them.
Show naming conventions that stay readable across a large schema, and the cost of renaming a reverse name that callers already use.
Set a project convention for reverse names, including default_related_name and the '+' pattern for audit keys, so relations read the same across apps.
## Every relation has two ends When a `Book` model declares `author = models.ForeignKey(Author, on_delete=models.PROTECT)`, Django adds two things: - A **forward accessor** on `Book`: `book.author` returns an `Author`. - A **reverse relation** on `Author`, which you never declared: a manager that returns the author's books, and a name you can use in queryset lookups that start from `Author`. `related_name` and `related_query_name` are how you name that reverse side. ## The defaults | Setting | Controls | Default | |---|---|---| | `related_name` | reverse **accessor** on the target (`author.<name>`) | `<model>_set`, e.g. `book_set` (for a `OneToOneField`, the lowercased model name) | | `related_query_name` | reverse **lookup** name in filters from the target | `related_name` if set, else `Meta.default_related_name`, else the lowercased model name, `book` | Two consequences surprise people: 1. With no `related_name`, the accessor and the lookup **differ**: you write `author.book_set.all()` but filter with `Author.objects.filter(book__title=...)`. 2. Setting `related_name="books"` renames **both**, because the query name defaults to it: now it is `author.books.all()` and `Author.objects.filter(books__title=...)`. If you want the lookup to stay singular, set `related_query_name="book"` explicitly. `Meta.default_related_name` sets a model-wide default for all of its relations, which keeps names consistent in a large app. ## When you are forced to set them Django validates reverse names with its **system checks** at startup: 1. **Two relations to the same target.** In a publisher's catalog, a `Book` has an `author` and a `translator`, both pointing at `Author`. Both would claim `author.book_set`; the checks raise `fields.E304` (reverse accessor clash) and `fields.E305` (reverse query name clash) until you give each its own `related_name`, say `authored_books` and `translated_books`. 2. **A reverse name colliding with a real field.** If `Author` already has a field called `books`, a relation cannot use that reverse name either (checks `fields.E302`/`fields.E303`). 3. **Abstract base classes.** A relation declared on an abstract model is copied into every subclass, so a fixed `related_name` would clash between subclasses. Use the placeholders: `related_name="%(app_label)s_%(class)s_related"`, where `%(class)s` is the lowercased subclass name and `%(app_label)s` its app label. 4. **Recursive many-to-many relations through an intermediary model**, where Django cannot pick distinct reverse names; at least one side needs a `related_name`. ## Turning the reverse side off Setting `related_name="+"`, or ending it with `+`, tells Django not to create the reverse accessor. It is handy for audit fields like `created_by` pointing at the user model, where you never want `user.<something>_set` and do not want to pick a name for it. ## Reading the names back A short shell session shows both names at work once `Book.author` has `related_name="authored_books"` and `related_query_name="authored_book"`: ```python author = Author.objects.get(name="Ada Park") author.authored_books.all() # reverse accessor Author.objects.filter(authored_book__title="Harbor Lights") # reverse query name Book.objects.filter(author__name="Ada Park") # forward lookup, unaffected ``` The forward side (`book.author`, `author__name` from `Book`) never changes; only the two reverse names do. If you later remove `related_query_name`, the filter name silently becomes `authored_books`, which is why a rename should be followed by a search for the old lookup strings as well as the old accessor. ## Naming guidance - Name the accessor from the **target's** point of view, plural for many: `publisher.books`, `author.authored_books`. - Keep the lookup name deliberate: plural lookups read oddly in filters, so some teams set `related_query_name` to the singular. - Prefer `settings.AUTH_USER_MODEL` for user references and give each such key a distinct `related_name`, since many models point at users. - Renaming a `related_name` touches no table, but it breaks every caller that used the old accessor or lookup, so search the codebase for both forms. Interviewers use this question to see whether a candidate knows that the reverse side exists at all, and that two separate names govern it.
- Why does a ForeignKey with related_name="books" on an abstract base model break once two concrete subclasses exist?The field is copied into each subclass, so both would add `books` to the same target and the reverse accessors clash. Use `related_name="%(app_label)s_%(class)s_related"` (and the same placeholders in `related_query_name`) so every subclass gets a name derived from its own app label and lowercased class name.
- What does related_name="+" do in Django, and when would you use it?It stops Django creating the reverse accessor on the target model. It suits bookkeeping keys such as `created_by = ForeignKey(settings.AUTH_USER_MODEL, ..., related_name="+")`, where nobody needs `user.<x>_set` and you would otherwise have to invent a unique name for every such field.
saying these in an interview costs you the question
- related_name only changes the database column name of the foreign key.
- Without related_name, filters use book_set__title as the lookup.
- Setting related_name leaves the reverse filter name unchanged.
- Two ForeignKeys to the same model work without any naming changes.
- related_name="+" deletes the foreign key constraint.