Создание сайта на Python/Django: взаимодействуем с API

Продолжаем разбираться в процессе разработки сайта на Django и запуска его в продакшн. В прошлом выпуске говорили о выборе хостинга для Django-проекта. В этой части серии публикаций предлагаю немного познакомиться с тем, как Django работает внутри и как можно с ним взаимодействовать на уровне консоли. Для этого в терминале запустим:

python manage.py shell

manage.py здесь включать обязательно, чтобы подключить переменные из окружения, которые хранятся в settings.py файле. Находясь в консоли, для начала подключим модели, чтобы можно было к ним обращаться:

>>> from polls.models import Choice, Question
# Далее выполним команду 
>>> Question.objects.all()
<QuerySet []>

Тут мы получили пустой ответ, т.к. в нашей БД еще нет записей с вопросами. Следовательно, попробуем сейчас добавить вопрос прямо из консоли. Вспоминаем, что наша модель Question, описанная в файле models.py, содержим два поля question_text и pub_date. С первым поле все более-менее ясно, это символьное поле куда мы зададим текст вопроса. Поле pub_date это поле даты и времени, когда вопрос был добавлен. Будем использовать функцию timezone.now() для определения текущего значения времени и даты и записи их в БД. Перед этим подключим соответствующий модуль Django.

>>> from django.utils import timezone
>>> q = Question(question_text="Что нового?", pub_date=timezone.now())
# Следующей командой сохраняем данные в БД:
>>> q.save()

После выполнения этих команд в нашей БД уже появилась одна запись в таблице Questions. Убедимся в этом, выполнив команду q.id, в ответ которой мы получим id последний последней записи. В нашем случае это 1.

>>> q.id
1

Попробуем получить доступ к другим полям записи, используя имена полей в качестве атрибутов.

>>> q.question_text
'Что нового?'
>>> q.pub_date
datetime.datetime(2019, 3, 23, 7, 43, 26, 65120, tzinfo=<UTC>)

Мы так же можем менять значения полей. Для начала присваиваем атрибуту новое значение, а потом сохраняем его вызовом save().

>>> q.question_text = "Что происходит?"
>>> q.save()
>>> q.question_text
'Что происходит?'
# Увидеть все записи в таблице Questions можно командой:
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

Обратите внимание, что результат выводится в виде типов данных, что не очень информативно и понятно. Мы можем исправить это, добавив к нашей модели пару строчек кода:

from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

Важно добавлять метод __str__() в модели не только для удобства вывода данных в интерактивной консоли, но и для удобного представления в админпанели Django, о которой речь пойдет немного позже.

Помимо __str()__ в модель можно добавлять и другие методы, которые могут быть использованы для удобного представления и обработки данных модели. Например, мы можем добавить следующий код в модель Question, который проверит, была ли запись добавлена за последний день:

import datetime
from django.db import models
from django.utils import timezone

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Не стоит забывать импортировать модули из которых мы используем различные функции и методы для обработки данных в модели. Впрочем, даже если вы что-то забудете, то Python и Django вам обязательно об этом сообщат в виде какой-то ошибки.

Обратите внимание, что после внесения изменений в код модели необходимо перезапустить интерактивную консоль командой, выйдя из предыдущей сессии командой exit() и повторно выполнив python manage.py shell. Так же повторяем импорт необходимых модулей.

>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: Что происходит?>]>

Как видим, теперь нам выводит текст из поля question_text, а значит __str__() работает. Django предлагает наш широкие возможности для взаимодействия с базой данных:

# Вывод записи с конкретным id
>>> Question.objects.filter(id=1)
<QuerySet [<Question: Что происходит?>]>

# Поиск записей, которые начинаются с 'Что'
>>> Question.objects.filter(question_text__startswith='Что')
<QuerySet [<Question: Что происходит?>]>

# Отфильтровать записи за последний год
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: Что происходит?>

# Ошибка при попытке получить запись с несуществующим id
>>> Question.objects.get(id=2)
Traceback (most recent call last):
…
polls.models.Question.DoesNotExist: Question matching query does not exist.

# Проверим наш пользовательский метод на работоспособность
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

Теперь давайте добавим к вопросу несколько вариантов ответов. Для этого определим объект Question, к которому будем добавлять связанные объекты Choice.

>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
<QuerySet []>

Так как вариантов ответов еще нет, то вывод пустой. Создадим три варианта ответов:

>>> q.choice_set.create(choice_text='Ничего', votes=0)
<Choice: Ничего>
>>> q.choice_set.create(choice_text='Много чего', votes=0)
<Choice: Много чего>
>>> с = q.choice_set.create(choice_text='Очень много чего', votes=0)
<Choice: Очень много чего>

# Проверяем содержимое объекта с вариантами ответов
>>> q.choice_set.all()
<QuerySet [<Choice: Ничего>, <Choice: Много чего>, <Choice: Очень много чего>]>

# Количество объектов можно подсчитать так
>>> q.choice_set.count()
3

Django автоматически отслеживает связи между объектами в моделях. Для определения связи используется двойное подчеркивание. Причем, такой подход работает на много уровней связей от начального объекта. Так, например, мы можем выполнить следующую команду:

>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Ничего>, <Choice: Много чего>, <Choice: Очень много чего>]>

Как результат, получим набор объектов Choice, которые связаны с объектами Question и имеют дату публикации (pub_date) за последний год (year).

Удаление объекта Choice можно выполнить командой delete():

>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Ничего>, <Choice: Много чего>, <Choice: Очень много чего>]>
>>> c = q.choice_set.filter(choice_text__startswith='Очень много')
>>> c.delete()
(1, {'polls.Choice': 1})
>>> q.choice_set.count()
2

Более детально о связях между объектами БД можно почитать в документации – Related objects reference. Подробнее о применении двойного подчеркивания описано в Field lookups. Детальнее о взаимодействии с базой данных можно ознакомиться в статье руководства Making queries.

На этом эту часть серии Создание сайта на Python/Django буду завершать. В следующей публикации поговорим о Django Admin.

Добавить комментарий

Ваш адрес email не будет опубликован.

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.