Как в Django ORM фильтровать по полям связанных моделей?

«Как в Django ORM фильтровать по полям связанных моделей?» — вопрос из категории Django, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Django ORM для фильтрации и выполнения запросов через связанные модели используется синтаксис с двойным подчеркиванием (__). Это позволяет "переходить" по связям ForeignKey, ManyToManyField и OneToOneField прямо в методах filter(), exclude() и get().

Примеры использования:

Предположим, у нас есть следующие модели:

class Author(models.Model):
    name = models.CharField(max_length=100)

class Article(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='articles')
    tags = models.ManyToManyField(Tag)
  1. Прямая связь (ForeignKey): Фильтрация Article по полю name связанной модели Author.

    # Найти все статьи, написанные автором с именем 'John Doe'
    articles = Article.objects.filter(author__name='John Doe')
  2. Обратная связь (Reverse ForeignKey): Фильтрация Author по полю title его статей. Для этого используется related_name (articles) или имя модели в нижнем регистре с суффиксом _set (article_set).

    # Найти всех авторов, у которых есть статьи со словом 'Django' в заголовке
    authors = Author.objects.filter(articles__title__icontains='Django')
  3. Связь Many-to-Many: Синтаксис аналогичен связям ForeignKey.

    # Найти все статьи с тегом 'python'
    articles_with_python_tag = Article.objects.filter(tags__name='python')
  4. Цепочки связей: Можно строить длинные цепочки для доступа к полям через несколько моделей.

    # Найти статьи автора, чей профиль указывает страну 'USA'
    # (при условии, что у Author есть OneToOneField к Profile с полем country)
    Article.objects.filter(author__profile__country='USA')

Этот механизм является одной из самых мощных возможностей Django ORM, позволяя строить сложные и выразительные запросы к базе данных.