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

Ответ

В 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, позволяя строить сложные и выразительные запросы к базе данных.

Ответ 18+ 🔞

О, смотри-ка, какая хуйня интересная! Это ж про двойное подчёркивание в Джанго, да? Ну, это пиздец как удобно, если разобраться, а не тупить как Герасим из той истории, который только «Му-му» и мог сказать.

Вот представь, у тебя там модели связаны, как сука в лесу на собачьей свадьбе. Автор написал статью, у статьи теги — всё переплетено. И чтобы достать что-то через эти связи, не нужно городить огород из трёх запросов и рукописных JOIN'ов. Всё решается этими двумя чёрточками: __. Просто хуяк — и ты уже в соседней таблице фильтруешь.

Смотри, вот пример, чтоб не быть мудаком, который нихуя не понял:

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): Хочешь все статьи, где автор — «Вася Пупкин»? Да не вопрос, ёпта!

    articles = Article.objects.filter(author__name='Вася Пупкин')

    Видишь? author__name. Как будто говоришь ORM: «Слушай, пройди по связи author и посмотри там поле name. Если совпало — тащи сюда».

  2. Обратный переход (Reverse ForeignKey): А теперь наоборот: найти всех авторов, у которых в заголовке статей есть слово «Django». Тут уже из Author лезем в его статьи через related_name (или article_set, если лень было имя придумывать).

    authors = Author.objects.filter(articles__title__icontains='Django')

    И опять магия: articles__title__icontains. ORM сам догадается, как связать таблицы и сделать нужный JOIN. Красота, блядь!

  3. Связь Many-to-Many: С тегами — вообще та же хуйня. Хочешь статьи с тегом «python»?

    articles_with_python_tag = Article.objects.filter(tags__name='python')

    Никаких ручных промежуточных таблиц, никакой ебли с IN — просто tags__name и поехали.

  4. Цепочки, блядь! А вот это уже высший пилотаж, ёпта. Допустим, у автора есть OneToOneField на профиль, а в профиле — страна. И ты хочешь все статьи автора из США. Да хуй с ним, сделаем!

    Article.objects.filter(author__profile__country='USA')

    author__profile__country — вот так, тремя переходами, и ты уже в другой вселенной ищешь данные. ORM сам построит запрос так, что мало не покажется твоей базе данных.

В общем, эта штука — одна из самых охуенных возможностей Django ORM. Позволяет строить запросы такой сложности, что сам от себя офигеваешь, а код остаётся читаемым и коротким. Главное — не переборщить, а то можно такую хуйню наворотить, что запрос будет выполняться дольше, чем Герасим Муму топил.