Продолжаем разбираться в процессе разработки сайта на 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.