Django ORM и QuerySet
В этой главе ты узнаешь, как Django подключается к базе данных и сохраняет в неё информацию. Давай начнём!
Что такое QuerySet?
QuerySet, по сути, — список объектов заданной модели. QuerySet позволяет читать данные из базы данных, фильтровать и изменять их порядок.
Проще научиться на примере. Давай попробуем, согласна?
Интерактивная консоль Django
Открой свой локальный терминал (не на PythonAnywhere) и набери следующую команду:
command-line
(myvenv) ~/djangogirls$ python manage.py shell
Результат должен быть таким:
command-line
(InteractiveConsole)
>>>
Ты находишься в интерактивной консоли Django. По сути, это та же интерактивная консоль Python, но с магией Django :) Ты можешь использовать весь синтаксис Python, разумеется.
Все объекты
Давай попробуем вывести на экран все записи в нашем блоге. Ты можешь сделать это следующей командой:
command-line
>>> Post.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'Post' is not defined
Упс! Ошибка. Она говорит, что не существует объекта с именем Post. И это верно — мы забыли импортировать его!
command-line
>>> from blog.models import Post
Всё просто: мы импортируем модель Post
из blog.models
. Давай попробуем получить все записи блога ещё раз:
command-line
>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>]>
Это список записей, с которыми мы работали до этого! Мы создали их через панель администратора Django. Теперь же мы хотим создавать записи с помощью Python, так как же мы этого добьёмся?
Создаём объект
Создать объект Post в базе данных можно следующим образом:
command-line
>>> Post.objects.create(author=me, title='Sample title', text='Test')
Но у нас есть один недочёт: me
. Мы должны передать этой переменной экземпляр модели User
, который будет отвечать за автора записи. Как это сделать?
Давай для начала импортируем модель User:
command-line
>>> from django.contrib.auth.models import User
Какие пользователи есть в нашей базе данных? Попробуй эту команду:
command-line
>>> User.objects.all()
<QuerySet [<User: ola>]>
Это суперпользователь, которого мы создали ранее! Нам нужен его экземпляр:
command-line
>>> me = User.objects.get(username='ola')
Как ты можешь заметить, мы получили (get
) пользователя (User
) с именем username
'ola'. Шикарно! В твоём случае имя, конечно, может отличаться.
Теперь мы, наконец, можем создать наш пост:
command-line
>>> Post.objects.create(author=me, title='Sample title', text='Test')
<Post: Sample title>
Ура! Хочешь проверить, что всё работает?
command-line
>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>, <Post: Sample title>]>
Есть, ещё один пост в списке!
Добавляем записи
Можешь повеселиться и добавить ещё записей. 2-3 будет достаточно.
Фильтрация объектов
Важной особенностью QuerySets является возможность фильтровать объекты. Предположим, нам нужно найти все записи пользователя ola. Мы используем метод filter
вместо метода all
в Post.objects.all()
. В скобках мы укажем условия, по которым будет построена выборка записей. В нашей ситуации условием будет являться равенство поля author
переменной me
. В Django мы можем написать это следующим образом: author=me
. Теперь наш код выглядит следующим образом:
command-line
>>> Post.objects.filter(author=me)
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>
А может быть мы хотим получить все записи со словом 'title' в поле title
?
command-line
>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>, <Post: 4th title of post>]>
Примечание: обрати внимание на два символа нижнего подчёркивания (
_
) междуtitle
иcontains
. Django ORM использует этот синтаксис для разделения имён полей ("title") и операций или фильтров ("contains"). Если ты используешь только один символ нижнего подчёркивания, то получишь ошибку "FieldError: Cannot resolve keyword title_contains".
Ты также можешь получить список всех опубликованных записей. Мы просто отфильтруем записи по полю published_date
:
command-line
>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet []>
К сожалению, пост, который мы добавили в консоли Python, ещё не опубликован. Мы можем изменить это! Сначала выберем запись, которую мы хотим опубликовать:
command-line
>>> post = Post.objects.get(title="Sample title")
Дальше мы опубликуем её с помощью метода publish
!
command-line
>>> post.publish()
Теперь попробуй получить список опубликованных сообщений снова (нажми стрелку вверх 3 раза и затем enter
):
command-line
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: Sample title>]>
Сортировка объектов
QuerySets позволяет сортировать объекты. Давай попробуем сортировку по полю created_date
:
command-line
>>> Post.objects.order_by('created_date')
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>
Мы также можем изменить порядок на противоположный, добавив -
в начало условия:
command-line
>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: 4th title of post>, <Post: My 3rd post!>, <Post: Post number 2>, <Post: Sample title>]>
Соединение QuerySets
QuerySets можно сцеплять, создавая цепочки:
>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
<QuerySet [<Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>, <Post: Sample title>]>
Это мощный и удобный инструмент, позволяющий писать сложные запросы.
Отлично! Теперь ты готова к следующей части! Чтобы закрыть интерактивную консоль, набери:
command-line
>>> exit()
$