Понятие CRUD. Добавление записей в таблицу БД. Модуль django-extensions

Курс по Django: https://stepik.org/a/183363

Архив проекта: 19_sitewomen.zip

На предыдущем занятии мы с вами описали модель Women и создали на ее основе таблицу в БД, используя механизм миграций. Теперь пришло время научиться работать с этой таблицей, добавлять, выбирать, менять и удалять записи. По-английски все эти операции сокращенно определяются аббревиатурой CRUD по первым буквам английских слов:

  • Create – создание;
  • Read – чтение;
  • Update – изменение;
  • Delete – удаление.

Используя ORM фреймворка Django, мы увидим, как выполняются данные команды в базовом исполнении. Почти все проекты, построенные на Django используют его встроенную ORM, не переходя на уровень SQL-запросов. В этом часто просто нет необходимости, так как ORM предоставляет богатейшие возможности по работе с БД. Кроме того, это обеспечивает независимость программного кода от конкретной используемой СУБД и если в будущем потребуется изменить тип БД, то сделать это будет предельно просто. Наконец, ORM в Django хорошо оптимизирует запросы по скорости выполнения и частоте обращения к таблицам БД, а также обеспечивает защиту от SQL-инъекций. Благодаря этому, даже начинающий веб-программист сможет создавать грамотный код по работе с БД.

На этом занятии мы рассмотрим базовые операции с таблицами посредством ORM Django. Позже мы еще углубимся в эту тему, а пока важно лишь понять общий принцип работы с моделями, знать как добавлять, выбирать, изменять и удалять записи.

Итак, первое, что нужно хорошо себе представлять, это то, что каждый экземпляр модели Women представляет собой одну отдельную запись таблицы women_women (далее просто women).

То есть, когда мы выбираем записи, или создаем новые записи, то происходит работа именно с объектами класса Women. Сам же класс, как мы уже говорили, описывает структуру (набор и тип полей) таблицы.

Для демонстрации работы с ORM перейдем в консоль Django и в терминале выполним команду:

python manage.py shell

чтобы войти в консоль фреймворка. Первым делом выполним импорт модели:

from women.models import Women

Теперь, чтобы добавить новую запись в таблицу, нам достаточно создать экземпляр класса Women и передать в его конструктор значения именованных параметров, характеризующие поля таблицы:

Women(title='Анджелина Джоли', content='Биография Анджелины Джоли')

Мы видим, что объект был создан, но при этом были указаны только два аргумента. Дело в том, что атрибуты time_create и time_update у нас в модели инициализируются автоматически и определять их конкретными значениями нет необходимости. Поле is_published по умолчанию также принимает значение True. По идее, content тоже можно было бы не определять (из-за параметра blank=True), но я захотел, чтобы оно содержало короткую строку.

Если сейчас перейти в SQLiteStudio и посмотреть содержимое таблицы women_women, то никаких записей не увидим. Почему так произошло? Дело в том, что модели в Django по умолчанию являются «ленивыми», создание экземпляра класса еще не означает добавление записи в таблицу. Как вы понимаете, это сделано специально. Мы можем в разных местах программы создавать объекты моделей и только в последний момент запускать их на исполнение, то есть, заносить информацию в БД. Благодаря этому Django имеет возможность оптимизировать SQL-запросы и излишне не нагружать СУБД.

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

w1 = _

Здесь символ ‘_’ – это специальная ссылка, в которой сохраняется результат последней операции. Если вывести переменную w1, то увидим строку:

<Women: Women object (None)>

Здесь None – это номер id, который принимает определенное, уникальное числовое значение в момент помещения записи в таблицу. Это делается с помощью метода save():

w1.save()

и, выводя опять же эту переменную в консоль, получаем строку:

<Women: Women object (1)>

Видим, вместо None уже стоит значение 1, то есть, запись была добавлена непосредственно в таблицу и ей был присвоен идентификатор с номером 1. Перейдем в программу SQLiteStudio и убедимся, что данные в таблице действительно появились. Да, это так, причем остальные поля также были проинициализированы нужными значениями.

Непосредственно в программе, то есть, в консоли Django мы можем оперировать всеми этими данными через ссылку w1:

w1.id # идентификатор
w1.title # заголовок
w1.time_create # время добавления записи

и так по всем полям (атрибутам класса). Помимо этих стандартных атрибутов объекты моделей содержат еще один часто используемый атрибут:

w1.pk # значение primary key

который совпадает с атрибутом id. Зачем было сделано такое дублирование? Дело в том, что поле id в таблицах имеет важное значение: часто именно по нему устанавливаются связи между таблицами. Поэтому по соглашению в Django решили определить атрибут со строго определенным именем pk, который будет всегда доступен и содержать номер текущей записи, либо значение None, если оно не определено. Позже мы не раз будем обращаться к этому свойству, как к идентификатору записи.

Конечно, непосредственное добавление записи в таблицу выполнялось с помощью SQL-запроса к БД. Чтобы его увидеть, нам нужно сначала импортировать модуль connection:

from django.db import connection

и обратиться к коллекции queries:

connection.queries

В консоли появится список словарей из выполненных запросов. У этого словаря имеются два ключа: sql – текст SQL-запроса; time – время выполнения этого запроса.

Давайте для примера создадим еще одну запись:

w2 = Women(title='Энн Хэтэуэй', content='Биография Энн Хэтэуэй')

Список queries  остался прежним, так как запись еще не была добавлена в таблицу. Выполним команду:

w2.save()

Теперь в списке queries два запроса, а в таблице две записи. Эти два последних примера показывают, что объект класса Women можно наполнять информацией как угодно до момента непосредственной записи. Например, можно вначале создать экземпляр класса без аргументов:

w3 = Women()

а, затем, его локальным атрибутам присвоить требуемые значения:

w3.title = 'Джулия Робертс'
w3.content = 'Биография Джулии Робертс'

После вызова метода save, запись будет добавлена в таблицу:

w3.save()

Установка улучшенной консоли ipython

Обратите внимание, что консоль фреймворка Django не очень удобна в работе, она даже не подсказывает нам возможные варианты команд, модулей и тому подобное. Но ее достаточно легко можно улучшить, установив специальный пакет ipython. Для этого в PyCharm перейдем в меню:

File->Settings

И в появившемся окне выберем Project:sitewomen->Python Interpreter. Нажмем на «плюс» и в строке поиска наберем ipython. Нажмем на кнопку «Install Package». Пакет будет установлен для текущего выбранного интерпретатора.

Запустим снова консоль фреймворка Django командой:

python manage.py shell

и увидим несколько другое оформление. Но что изменилось в функциональности? Смотрите, если теперь начать вводить какую либо команду, например:

fr

и нажать на кнопку Tab, то увидим возможные варианты. Последующие нажатия на Tab будут подставлять соответствующие команды. Наберем:

from women.models import Women

Видите, как это стало проще и удобнее? Выйдем из консоли с помощью команды exit.

Установка улучшенной пакета django-extensions

В заключение этого занятия давайте установим еще один пакет, который может упростить отработку ORM-команд в консоли. Он называется django-extensions и устанавливается аналогично предыдущему пакету:

https://github.com/django-extensions/django-extensions

После установки согласно документации мы должны его прописать в коллекции INSTALLED_APPS файла конфигурации settings.py. Сделаем это:

INSTALLED_APPS = [
    ...
    'django_extensions',
    'women.apps.WomenConfig',
]

После этого, нам становится доступна новая команда shell_plus, которую выполним с ключом --print-sql:

python manage.py shell_plus --print-sql

Запустится новая оболочка с поддержкой ранее установленного ipython и с автоматической распечаткой        выполняемых SQL-запросов. Давайте в этом убедимся. Создадим объект класса Women (в оболочке shell_plus модели импортируются автоматически):

a = Women(title="Екатерина Гусева", content="Биография Екатерины Гусевой")

и вызовем метод save():

a.save()

В результате нам автоматически выводится SQL-запрос, который добавил эту запись в БД. И это гораздо удобнее, чем каждый раз смотреть его в коллекции queries модуля connection.

Курс по Django: https://stepik.org/a/183363

Видео по теме