При проведении миграции Django модифицирует базу данных, чтобы в ней хранилась связь между каждой темой и пользователем. Для выполнения миграции Django необходимо знать, с каким пользователем должна быть связана каждая существующая тема. Проще всего связать все существующие темы с одним пользователем, например суперпользователем. Но для этого сначала необходимо узнать идентификатор этого пользователя.
Просмотрим идентификаторы всех пользователей, созданных до настоящего момента. Запустите сеанс оболочки Django и введите следующие команды:
(venv)learning_log$ python manage.py shell
(1) >>> from django.contrib.auth.models import User
(2)>>> User.objects.all()
[
(3)>>> for user in User.objects.all():
... . . print(user.username, user.id)
...
ll_admin 1
eric 2
willie 3
>>>
В точке (1) в сеанс оболочки импортируется модель User. После этого просматриваются все пользователи, созданные до настоящего момента (2). В выходных данных перечислены три пользователя: ll_admin, eric и willie.
В точке (3) перебирается список пользователей, и для каждого пользователя выводится его имя и идентификатор. Когда Django спросит, с каким пользователем связать существующие темы, мы используем один из этих идентификаторов.
Миграция базы данных
Зная значение идентификатора, можно провести миграцию базы данных.
(1) (venv)learning_log$ python manage.py makemigrations learning_logs
(2)You are trying to add a non-nullable field 'owner' to topic without a default;
we can't do that (the database needs something to populate existing rows).
(3)Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
(4)Select an option: 1
(5)Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do
e.g. timezone.now()
? >>> 1
Migrations for 'learning_logs':
0003_topic_owner.py:
. .- Add field owner to topic
Сначала выдается команда makemigrations (1) . В ее выходных данных (2) Django сообщает, что мы пытаемся добавить обязательное поле (значения которого отличны от null) в существующую модель (topic) без указания значения по умолчанию. Django предоставляет два варианта (3): мы можем либо указать значение по умолчанию прямо сейчас, либо завершить выполнение программы и добавить значение по умолчанию в models.py. В точке (4) выбирается первый вариант. Тогда Django запрашивает значение по умолчанию (5).
Чтобы связать все существующие темы с исходным административным пользователем ll_admin, я ввел в точке ? идентификатор пользователя 1. Вы можете использовать идентификатор любого из созданных пользователей; он не обязан быть суперпользователем. Django проводит миграцию базы данных, используя это значение, и создает файл миграции 0003_topic_owner.py, добавляющий поле owner в модель Topic.
Теперь можно провести миграцию. Введите следующую команду в активной виртуальной среде:
(venv)learning_log$ python manage.py migrate
Operations to perform:
Synchronize unmigrated apps: messages, staticfiles
Apply all migrations: learning_logs, contenttypes, sessions, admin, auth
...
Running migrations:
Rendering model states... DONE
(1) Applying learning_logs.0003_topic_owner... OK
(venv)learning_log$
Django применяет новую миграцию с результатом OK (1) . Чтобы убедиться в том, что миграция сработала так, как и ожидалось, можно воспользоваться интерактивной оболочкой:
(1) >>> from learning_logs.models import Topic
(2)>>> for topic in Topic.objects.all():
... . . print(topic, topic.owner)
...
Chess ll_admin
Rock Climbing ll_admin
>>>
После импортирования Topic из learning_logs.models (1) мы перебираем все существующие темы, выводим каждую тему и имя пользователя, которому она принадлежит (2). Как видите, сейчас каждая тема принадлежит пользователю ll_admin.
Примечание
Вместо миграции можно просто сбросить содержимое базы данных, но это приведет к потере всех существующих данных. Полезно научиться выполнять миграцию базы данных без нарушения целостности данных пользователей. Если вы хотите начать с новой базы данных, используйте команду python manage.py flush для повторного построения структуры базы данных. Вам придется создать нового суперпользователя, а все данные будут потеряны.
Ограничение доступа к темам
В настоящее время пользователь, выполнивший вход, будет видеть все темы независимо от того, под какой учетной записью он вошел. Сейчас мы изменим приложение, чтобы каждый пользователь видел только принадлежащие ему темы.
Внесите следующее изменение в функцию topics() в файле views.py:
views.py
...
@login_required
def topics(request):
"""Выводит список тем."""
. .topics = Topic.objects.filter(owner=request.user).order_by('date_added')