Изменение схемы базы данных Django

Опубликовал: Saturday, February 4, 2024 в категории Django | Пока нет комментариев

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

Но сначала упомянем некоторые особенности работы уровня доступа к базе данных в Django.

•      Django будет «громко возмущаться», если модель содержит поле, отсутствующее в таблице базы данных. Ошибка произойдет при первой же попытке воспользоваться API для выполнения запроса к данной таблице (то есть на этапе выполнения, а не компиляции).

•      Django безразлично, что в таблице могут быть столбцы, не определенные в модели.

•      Django безразлично, что в базе данных могут быть таблицы, не представленные моделью.

Изменение схемы сводится к изменению различных частей - кода на Python и самой базы данных - в определенном порядке. Каком именно, описано в следующих разделах.

Добавление полей

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

Однако тут мы сталкиваемся с проблемой курицы и яйца - чтобы узнать, как описать новый столбец базы данных на языке SQL, нам нужно взглянуть на результат команды manage.ру sqlall, а для этого необходимо, чтобы поле уже существовало в модели. (Отметим, что необязательно создавать столбец точно той же командой SQL, которую использовал бы Django, но все же разумно поддерживать единообразие.)

Решение проблемы состоит в том, чтобы сначала внести изменения в среде разработки, а не сразу на действующем сервере. (У вас ведь настроена среда для разработки и тестирования, правда?) Ниже подробно описывается последовательность действий.

Сначала нужно выполнить следующие действия в среде разработки:

1.     Добавить поле в модель.

2.     Выполнить команду manage.ру sqlall [ваше приложение] и посмотреть на созданную ею команду CREATE TABLE для интересующей вас модели. Записать, как выглядит определение нового столбца.

3.     Запустить интерактивный клиент СУБД (например, psql или mysql, либо просто команду manage.ру dbshell). Добавить столбец командой ALTER TABLE.

4.     Запустить интерактивный интерпретатор Python командой manage, ру shell и убедиться, что новое поле добавлено правильно. Для этого следует импортировать модель и выбрать записи из таблицы (например, MyModel.objects.all()[:5]). Если все было сделано правильно, то это предложение отработает без ошибок.

Затем можно выполнить следующие действия на действующем сервере:

1.     Запустить интерактивный клиент СУБД.

2.     Выполнить ту же команду ALTER TABLE, которая использовалась на третьем шаге при добавлении столбца в среде разработки.

3.     Добавить поле в модель. Если вы пользуетесь системой управления версиями и на шаге 1 при добавлении столбца в среде разработки вы вернули измененную модель в репозиторий, то теперь самое время синхронизировать локальную копию кода на действующем сервере (в случае Subversion это делается командой svn update).

4.     Перезапустить веб-сервер, чтобы изменения вступили в силу.

Проиллюстрируем эту процедуру на примере добавления поля num_pages в модель Book из главы 5. Сначала изменим модель в среде разработки:

class Book(models.Model):

title = models.CharField(max_length=100)

authors = models.ManyToManyField(Author)

publisher = models.ForeignKey(Publisher)

publication_date = models.DateField()

num_pages = models.IntegerField(blank=True, null^True)

def ______ unicode__(self):

return self.title

Примечание ———————————————————————-

Если хотите знать, зачем включены атрибуты blank=True и null=True, прочитайте раздел «Как сделать поле необязательным» в главе 6 и врезку «Добавление полей со спецификатором NOT NULL».

Добавление полей со спецификатором NOT NULL

Мы хотели привлечь ваше внимание к одной тонкости. При добавлении в модель поля num_pages мы указали атрибуты blank=True и null=True, поэтому сразу после создания новый столбец будет содержать NULL во всех записях таблицы.

Но можно добавить и столбец, не допускающий NULL. Для этого сначала следует создать его со значением NULL, затем заполнить столбец каким-нибудь значением по умолчанию и, наконец, изменить определение столбца, добавив спецификатор NOT NULL. Например:

ALTER TABLE books_book ADD COLUMN num_pages integer; UPDATE books_book SET num_pages=0;

ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL; COMMIT;

Но если вы решите идти этим путем, не забудьте убрать атрибуты blank=True и null=True из описания столбца в модели.

Далее следует выполнить команду manage.ру sqlall и взглянуть на созданную команду CREATE TABLE. Она должно выглядеть примерно так (точный вид зависит от СУБД):

CREATE TABLE "books_book" (

"id" serial NOT NULL PRIMARY KEY, "title" varchar(IOO) NOT NULL,

"publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"),

"publication_date" date NOT NULL, "num_pages" integer NULL

);

Новому столбцу соответствует строка:

"num_pages" integer NULL

Теперь запустим интерактивный клиент для тестовой базы данных, набрав psql (в случае PostgreSQL) и выполним команду:

ALTER TABLE books_book ADD COLUMN num_pages integer;

Выполнив команду ALTER TABLE, проверим, что все работает нормально. Для этого запустим интерпретатор Python и выполним такой код:

»> from mysite.books.models import Book »> Book.objects.all()[ :5]

Если все прошло без ошибок, то перейдем на действующий сервер и выполним там команду ALTER TABLE. Затем обновим модель в действующей среде и перезапустим веб-сервер.

Удаление полей

Удалить поле из модели проще, чем добавить. Нужно лишь выполнить следующие действия:

1.           Удалить описание поля из класса модели и перезапустить веб-сервер.

2.           Удалить столбец из базы данных, выполнив команду, такую как

ALTER TABLE books_book DROP COLUMN num_pages;

Действовать надо именно в таком порядке. Если сначала удалить столбец из базы, то Django сразу же засыплет вас сообщениями об ошибках.

Удаление полей типа многие-ко-многим

Поскольку поля, описывающие отношения типа многие-ко-многим, отличаются от обычных, то и процедура их удаления выглядит иначе.

1.     Удалить описание поля типа ManyToManyField из класса модели и перезапустить веб-сервер.

2.     Удалить связующую таблицу из базы данных командой, такой как DROP TABLE books_book_authors;

И снова подчеркнем, что действовать надо именно в таком порядке.

Удаление моделей

Удалить модель так же просто, как и поле. Требуется выполнить следующие действия:

1.          Удалить класс модели из файла models, ру и перезапустить веб-сервер.

2.          Удалить таблицу из базы данных командой, такой как

DROP TABLE books_book;

Отметим, что может понадобиться сначала удалить из базы данных зависимые таблицы, например, ссылающиеся на books_book по внешнему ключу.

Опять же не забудьте, что действовать надо в указанном порядке.

Источник: Головатый А., Каплан-Мосс Дж. Django. Подробное руководство, 2-е издание. - Пер. с англ. - СПб.: Символ- Плюс, 2010. - 560 е., ил.

Похожие посты:

Комментировать

Your email address will not be published. Required fields are marked *