Фильтрация данных

В этой статье мы будем работать с моделями данных. Если вам не знаком этот термин, обратитесь к этой статье.

Итак, допустим, у вас есть модель Post, которая описывает статью в блоге:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    text = models.TextField()

    is_deleted = models.BooleanField()
    is_published = models.BooleanField()

У модели есть 2 интересных поля: is_deleted и is_published. Эти поля хранят 2 вида значений: либо True, либо False.

Фильтрация

На главной странице блога обычно показывают все опубликованные статьи. То есть не все, а те, у которых is_published == True. Вот так можно получить их список:

posts = Post.objects.all()
published_posts = []
for post in posts:
    if post.is_published:
        published_posts.append(post)

Здесь мы достаём все посты из БД, а затем выбираем из них опубликованные.

Оказывается, в Django ORM можно сразу попросить прислать только опубликованные посты:

published_posts = Post.objects.filter(is_published=True)

is_published — это название поля из модели данных Post. В filter можно указать название любого поля, из тех, что есть у модели данных:

deleted_posts = Post.objects.filter(is_deleted=True)
non_published_posts = Post.objects.filter(is_published=False)
non_deleted_posts = Post.objects.filter(is_deleted=False)

Если подходящие объекты не найдутся, вам вернётся пустой QuerySet. Он ведёт себя как пустой список.

Фильтрация по нескольким полям

Кажется, мы совсем забыли про поле is_deleted. Если пост удалён, то его не нужно показывать на главной. Получается, нужно показать опубликованные посты и скрыть все удалённые. Можно сделать это так:

posts_to_show = Post.objects.filter(is_published=True, is_deleted=False)

filter умеет комбинировать несколько условий

Операции сравнения

Если пользователь ищет на вашем сайте статьи со словом "питон", то привычный способ фильтрации вам не поможет:

search_phrase = "питон"
searched_posts = Post.objects.filter(title="питон")

Здесь база данных будет искать посты, у которых заголовок в точности равен строке "питон". А нам нужны статьи со словом "питон" в заголовке:

Питон для новичков
Джаваскрипт vs Питон
Питон в естественной среде обитания

Поможет операция сравнения contains. Она позволит вам проверить, что заголовок содержит строку "питон":

searched_posts = Post.objects.filter(title__contains="питон")

Все операции сравнения начинаются с двух подчёркиваний и прямо "приписываются" к полям. Есть и другие операции сравнения, например, __gt и __lt:

__gt — (greater then, в переводе, "больше чем") проверяет, что поле больше, чем то, что передадут справа. Пример: filter(likes__gt=10) — фильтруем посты, у которых больше 10 лайков.

__lt — (less then, "меньше чем) аналогично, проверяет, что поле меньше.

Чтобы проверить условие "больше или равно", есть операция сравнения __gte, а "меньше ли равно" — __lte.

Операции сравнения — фича Django ORM

Операции сравнения с двумя подчёкиваниями работают только в методах filter, exclude и get из Django ORM и нигде больше. Не пытайтесь использовать это в работе с другими библиотеками и функциями, они не поймут.

Что читать дальше