Языки программирования

Модели и миграции в Django

Модели

Модель — это однозначное и исчерпывающее описание сущности, хранящейся в базе данных в виде класса Python.
Класс модели описывает таблицу базы данных, в которой будет храниться набор сущностей, и содержит атрибуты класса (в других языках программирования их называют свойствами класса, или статическими свойствами), каждый из которых описывает одно из полей этой таблицы.
Отдельный экземпляр класса представляет отдельную конкретную сущность, извлеченную из базы данных, т.е. отдельную запись соответствующей таблицы.
Помимо этого, класс модели предоставляет инструменты для выборки сущностей из базы данных, их фильтрации и сортировки на основе заданных критериев. Полученный результат представляется в виде последовательности экземпляров класса модели.
Модели объявляются на уровне приложения. Объявляющий их код должен записываться в модуль models.py пакета приложения. Для примера, объявим модель «Bb», которая будет представлять объявление со следующими полями:
  • title — заголовок объявления, содержащий название продаваемого товара (тип — строковый, длина — 50 символов). Поле, обязательное к заполнению;
  • content — текст объявления, описание товара (тип — memo);
  • price — цена (тип — вещественное число);
  • published — дата публикации (тип — дата и время, значение по умолчанию — текущие дата и время, индексированное).
В нашем прошлом проекте откроем модуль models.py пакета приложения «btest» и запишем в него код:
from django.db import models

class Bb(models.Model):
  title = models.CharField(max_length=50)
  content = models.TextField(null=True, blank=True)
  price = models.FloatField(null=True, blank=True)
  published = models.DateTimeField(auto_now_add=True, db_index=True)
Модель должна быть подклассом класса Model из модуля django.db.models. Рассмотрим использованные нами классы полей и их параметры:

  • CharField — обычное строковое поле фиксированной длины;
  • TextField — текстовое поле неограниченной длины, или memo-поле. Присвоив параметрам null и blank конструктора значения True, мы укажем, что это поле можно не заполнять;
  • FloatField — поле хранения вещественных чисел;
  • DateTimeField — поле для хранения отметки даты и времени. Присвоив параметру auto_now_add конструктора значения True. Параметр db_index при присваивании ему значения True укажет создать для этого поля индекс.

После написания кода сохраним файл. Далее с помощью миграции мы создадим в базе данных необходимые структуры.

По умолчанию созданный проект Django настроен на использование базы данных в формате SQLite, хранящейся в файле db.sqlite3 в папке проекта. Данная база данных будет создана при первом запуске отладочного web-сервера.

Для работы с базами данных в проекте Django в файле settings.py определен параметр DATABASES, который по умолчанию выглядит следующим образом:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
Конфигурация используемой базы данных в данном случае складывается из двух параметров. Параметр ENGINE указывает на используемый движок для доступа к БД.

В данном случае это встроенный пакет django.db.backends.sqlite3. Второй параметр — NAME указывает на путь к базе данных.

Чтобы использовать другие системы управления базами данных, необходимо будет установить соответствующий пакет:

Миграции

Миграция — это модуль Python, созданный самим Django на основе определенной модели и предназначенный для формирования в базе данных всех требуемых этой моделью структур.
Для формирования миграции на основе модели «Bb» перейдем в командную строку нашего проекта, и дадим команду:
manage.py makemigrations btest
Команда makemigrations утилиты manage.py запускает генерирование миграций для всех моделей, объявленных в приложении, чье имя записано после команды, и не изменившихся с момента предыдущего генерирования миграций.
Сформированные таким образом модули с миграциями сохраняются в пакете migrations, находящемся в пакете приложения. Модуль с кодом нашей первой миграции будет иметь имя 0001_initial.py. Откроем его и просмотрим код:
from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Bb',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=50)),
                ('content', models.TextField(blank=True, null=True)),
                ('price', models.FloatField(blank=True, null=True)),
                ('published', models.DateTimeField(auto_now_add=True, db_index=True)),
            ],
        ),
    ]
Миграция при выполнении порождает команды на языке SQL, которые будут отправлены СУБД, и, собственно, выполняет все действия по созданию необходимых структур данных. Посмотрим на результирующий SQL-код нашей миграции через командную строку:
manage.py sqlmigrate btest 0001
Результат команды:
Первое выполнение миграций рекомендуется производить для всех приложений, входящих в проект. Для этого наберём в командной строке команду выполнения всех миграций всех приложений проекта:
manage.py migrate
Результат:

Консоль Django

Фреймворк включает в свой состав собственную редакцию консоли Python Shell, называемую консолью Django. Для её запуска напишем в командной строке команду для запуска консоли:
manage.py shell

Работа с моделями

Создадим первое объявление — первую запись модели Bb:
from btest.models import Bb
b1 = Bb(title='Дом', content='ООО "Агент". Два этажа, кирпич, свет, газ, канализация', price=10000000)
Созданная таким образом запись модели не сохраняется в базе данных. а существует только в оперативной памяти. Чтобы сохранить её, достаточно вызвать у неё метод save() без параметров:
b1.save()
Проверить сохранилось ли первое объявление можно, получив значение ключевого поля:
b1.pk

#Выведет: 1
Атрибут класса pk, поддерживаемый всеми моделями, хранит значение ключевого поля текущей записи. Это значение может быть получено только после того, как запись модели успешно сохранится в базе данных.

Можно обратиться к любому полю записи, воспользовавшись соответствующим ему атрибутом класса модели. Например:
b1.title

#Выведет: 'Дом'
Для закрепления материала создадите еще несколько объявлений. Пример:
Другой вариант добавления:
Bb.objects.create(title='Дача', content='Один этаж. Брус.', price=100000000)
Все классы моделей поддерживают атрибут класса objects. Он хранит диспетчер записей — особую структуру, позволяющую манипулировать всей совокупностью имеющихся в модели записей. Диспетчер записей представляется экземпляром класса Manager.

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

За удаление записей отвечает метод delete().

После добавления записей выйдем из консоли Django набрав команду:
exit()
Откроем модуль views.py пакета приложения «btest» и исправим код для вывода наших объявлений:
from django.http import HttpResponse
from .models import Bb

def index(request):
  s = 'Список объявлений\r\n\r\n\r\n'
  for bb in Bb.objects.order_by('-published'):
    s += bb.title + '\r\n' + bb.content + '\r\n\r\n'
  return HttpResponse(s, content_type='text/plain; charset=utf-8')
Список объявлений мы представили в виде обычного текста, разбитого на строки последовательностью специальных символов возврата каретки и перевода строки: \r\n. order_by сортирует записи по убыванию даты.

При создании экземпляра класса HttpResponse, представляющего отсылаемый клиенту ответ, мы в именованном параметре content_type конструктора указали тип отправляемых данных: обычный текст, набранный в кодировке UTF-8 (если этого не сделать, браузер посчитает текст HTML-кодом и выведет его одной строкой).

Сохраним исправляемый файл и запустим отладочный web-сервер с помощью команды «manage.py runserver». Результат:
Фреймворк Django