Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Django_-_podrobnoe_rukovodstvo

.pdf
Скачиваний:
306
Добавлен:
01.03.2016
Размер:
4.88 Mб
Скачать

100

 

 

Глава 5. Модели

Таблица 5.2. Сообщения об ошибках конфигурации базы данных

 

Сообщение об ошибке

 

Решение

 

 

 

 

 

 

 

You haven’t set the DATABASE_ENGINE

 

Параметр DATABASE_ENGINE не должен

 

setting yet.

 

быть пустой строкой. Допустимые

 

(Вы еще не задали параметр DATABASE_

 

значения приведены в табл. 5.1.

 

 

 

 

ENGINE)

 

 

 

Environment variable DJANGO_SETTINGS_

 

Выполните команду python manage.

 

MODULE is undefined.

 

py, а не просто python.

 

(Не определена переменная окружения

 

 

 

DJANGO_SETTINGS_MODULE)

 

 

 

Error loading _____ module:

 

Не установлен нужный адаптер

 

No module named _____.

 

базы данных (например, psycopg

 

(Ошибка при загрузке модуля ____:

 

или MySQLdb). Адаптеры не

 

 

входят в дистрибутив Django, вы

 

Модуль _____ не существует)

 

 

 

должны скачать и установить их

 

 

 

 

 

 

самостоятельно.

 

_____ isn’t an available database

 

Значением параметра DATABASE_

 

back-end.

 

ENGINE должна быть одна из

 

(СУБД ____ не поддерживается)

 

перечисленных выше строк. Быть

 

 

может, опечатка?

 

 

 

 

Database _____ does not exist

 

Измените параметр DATABASE_

 

(База данных ____ не существует)

 

NAME, так чтобы он указывал на

 

 

существующую базу данных, или

 

 

 

 

 

 

создайте нужную базу данных

 

 

 

командой CREATE DATABASE.

 

Role _____ does not exist

 

Измените параметр DATABASE_

 

(Роль ____ не существует)

 

USER, так чтобы он указывал на

 

 

существующего пользователя, или

 

 

 

 

 

 

создайте нужного пользователя

 

 

 

в своей базе данных.

 

Could not connect to server

 

Убедитесь, что параметры

 

(Не удалось подключиться к серверу)

 

DATABASE_HOST и DATABASE_PORT заданы

 

 

правильно, а сервер базы данных

 

 

 

 

 

 

запущен.

 

 

 

 

Ваше первое приложение

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

Сейчас стоит сказать несколько слов о терминологии, поскольку начинающие здесь часто спотыкаются. В главе 2 мы уже создали проект,

Ваше первое приложение

101

так чем же проект отличается от приложения? Тем же, чем конфигурация от кода.

•• Проект – это некоторый набор приложений Django плюс конфигурация этих приложений.

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

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

•• В комплект поставки Django входит несколько приложений, например, система­ подачи комментариев и автоматизированный административный интерфейс. Важно понимать, что эти приложения переносимы и могут использоваться в разных проектах.

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

На самом деле совершенно не обязательно вообще создавать приложения, что с очевидностью следует из примеров функций представлений, с которыми мы уже встречались выше. Мы просто создавали файл views. py, добавляли в него функции представлений и в конфигурации URL указывали на эти функции. Никаких «приложений» не понадобилось.

Однако с соглашением о приложениях связано одно требование: если в проекте используется уровень работы с базой данных (модели), то создавать приложение нужно обязательно. Поэтому перед тем, как приступить к написанию моделей, мы создадим новое приложение.

Находясь в каталоге проекта mysite, введите команду для создания приложения books:

python manage.py startapp books

Эта команда ничего не выводит в окне терминала, но создает каталог books внутри каталога mysite. Посмотрим, что в нем находится.

books/ __init__.py models.py tests.py views.py

В этих файлах будут храниться модели и представления для данного приложения.

102

Глава 5. Модели

Откройте файлы models.py и views.py в своем любимом текстовом редакторе. В обоих файлах ничего нет, кроме комментариев и директив импорта в файле models.py. Это просто заготовка для приложения Django.

Определение моделей на языке Python

Выше в этой главе мы сказали, что буква «M» в аббревиатуре «MTV» означает «Model». Модель в Django представляет собой описание данных в базе, представленное на языке Python. Это эквивалент SQL-коман­ды­ CREATE TABLE, только написанный не на SQL, а на Python, и включающий гораздо больше, чем определения столбцов. В Django модель использу­ ется, чтобы выполнить SQL-код и вернуть удобные структуры данных Python, представляющие строки из таблиц базы данных. Кроме того, модели позволяют представить высокоуровневые концепции, для ко­ торых в SQL может не быть аналогов.

У человека, знакомого с базами данных, сразу же может возникнуть вопрос: «А нет ли дублирования в определении моделей данных на Python вместо SQL?» Django работает так по ряду причин:

•• Интроспекция сопряжена с накладными расходами и несовершенна. Чтобы предложить удобный API доступа к данным, Django необходимо как-то узнать о структуре базы данных, и сделать это можно двумя способами: явно описать данные на Python или опрашивать базу данных во время выполнения.

•• Второй способ, на первый взгляд, чище, так как метаданные о таб­ лицах находятся только в одном месте, но при этом возникает несколько проблем. Во-первых, опрос метаданных (интроспекция) во время выполнения, очевидно, обходится дорого. Если бы фреймворку приходилось опрашивать базу данных при каждом запросе или даже один раз при запуске веб-сервера, то накладные расходы оказались бы недопустимо высокими. (Хотя некоторые полагают, что такие издержки приемлемы, разработчики Django стремятся по возможности устранять накладные расходы самого фреймворка.) Вовторых, в некоторых СУБД – и в первую очередь в старых версиях MySQL – не хранится достаточно метаданных для точной и полной интроспекции.

•• Писать на Python вообще приятно, и если представлять все на этом языке, то сокращается количество мысленных «переключений контекста». Чем дольше разработчику удается оставаться в рамках одного программного окружения и менталитета, тем выше его продуктивность. Когда приходится писать код на SQL, потом на Python, а потом снова на SQL, продуктивность падает.

•• Размещение моделей данных в коде, а не в базе данных, упрощает их хранение в системе­ управления версиями. Поэтому становится легче отслеживать изменения в структуре данных.

Первый пример модели

103

•• SQL позволяет хранить лишь ограниченный объем метаданных. Так, в большинстве СУБД нет специального типа данных для представления адресов электронной почты или URL. А в моделях Django это возможно. Высокоуровневые типы данных повышают продуктивность и степень повторной используемости кода.

•• Диалекты SQL в разных СУБД несовместимы между собой. При распространении веб-приложения гораздо удобнее включить в дистрибутив один модуль на Python, описывающий структуру данных, чем отдельные наборы команд CREATE TABLE для MySQL, PostgreSQL и SQLite.

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

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

Первый пример модели

В этой и в следующей главе мы будем работать с базой данных, хранящей информацию о книгах, авторах и издательствах. Мы решили остановиться на этом примере, потому что концептуальные отношения между книгами, авторами и издательствами хорошо известны и разобраны во многих учебниках по SQL. Да и сейчас вы читаете книгу, которая написана авторами и опубликована издательством!

Мы принимаем следующие допущения:

•• У автора есть имя, фамилия и адрес электронной почты.

•• У издательства есть название, адрес, город, штат или область, страна и адрес в Интернете.

•• У книги есть название и дата публикации, а также один или несколько авторов (отношение многие-ко-многим между книгами и авторами) и единственное издательство (отношение один-ко-многим с издательствами, иначе называемое внешним ключом).

Самый первый шаг при использовании такой структуры базы данных

вDjango – выразить ее в виде кода на Python. Введите следующий текст

вфайл models.py, созданный командой startapp:

from django.db import models

class Publisher(models.Model):

104

Глава 5. Модели

name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60)

state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField()

class Author(models.Model):

first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField()

class Book(models.Model):

title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField()

На примере этого кода рассмотрим основные принципы. Прежде всего, отметим, что любая модель представлена классом, наследующим класс django.db.models.Model. Родительский класс Model содержит все необходимое, чтобы эти объекты могли взаимодействовать с базой данных, поэтому наши модели отвечают только за определение собственных полей, так что мы получаем красивую и компактную запись. Хотите верьте, хотите нет, но это все, что нужно для обеспечения простого доступа к данным в Django.

Вообще говоря, каждая модель соответствует одной таблице базы данных, а каждый атрибут модели – одному столбцу таблицы. Имя атрибута соответствует имени столбца, а тип поля (например, CharField) – типу столбца (например, varchar). Так, модель Publisher эквивалентна следующей таблице (использован синтаксис команды CREATE TABLE, принятый в PostgreSQL).

CREATE TABLE “books_publisher” ( “id” serial NOT NULL PRIMARY KEY, “name” varchar(30) NOT NULL, “address” varchar(50) NOT NULL, “city” varchar(60) NOT NULL,

“state_province” varchar(30) NOT NULL, “country” varchar(50) NOT NULL, “website” varchar(200) NOT NULL

);

На самом деле Django, как мы скоро увидим, может сгенерировать команду CREATE TABLE автоматически.

У правила «одна таблица базы данных – один класс» есть исключение, касающееся отношения многие-ко-многим. Так, в модели Book есть поле authors типа ManyToManyField. Это означает, что у книги может быть один или несколько авторов. Однако в таблице Book нет столбца authors. Поэтому Django создает дополнительную таблицу – связующую для отно-

Установка модели

105

шения многие-ко-многим, – которая и реализует отображение между книгами и авторами.

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

Наконец, отметим, что ни для одной модели мы не определили явно первичный ключ. Если не указано противное, Django автоматически включает в каждую модель автоинкрементный первичный ключ целого типа – поле id. Любая модель в Django должна иметь первичный ключ ровно по одному столбцу.

Установка модели

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

Откройте файл settings.py и найдите в нем параметр INSTALLED_APPS. Он сообщает Django, какие приложения в данном проекте активированы. По умолчанию этот параметр выглядит следующим образом:

INSTALLED_APPS = ( ‘django.contrib.auth’, ‘django.contrib.contenttypes’, ‘django.contrib.sessions’, ‘django.contrib.sites’,

)

Временно закомментируйте все четыре строки, поставив в начале каждой знак #. (По умолчанию они включены, так как часто используются, и мы еще активируем их в последующих главах.) Заодно закомментируйте заданный по умолчанию параметр MIDDLEWARE_CLASSES; подразумеваемые в нем значения по умолчанию зависят от только что закомментированных приложений. Затем добавьте в список INSTALLED_APPS строку ‘mysite.books’. Полученный в результате файл параметров должен выглядеть так:

MIDDLEWARE_CLASSES = (

#‘django.middleware.common.CommonMiddleware’,

#‘django.contrib.sessions.middleware.SessionMiddleware’,

#‘django.contrib.auth.middleware.AuthenticationMiddleware’,

)

INSTALLED_APPS = (

#‘django.contrib.auth’,

#‘django.contrib.contenttypes’,

#‘django.contrib.sessions’,

#‘django.contrib.sites’,

‘mysite.books’,

)

106

Глава 5. Модели

В предыдущей главе мы говорили, что единственная строка в списке TEMPLATE_DIRS должна завершаться запятой. То же относится и к списку INSTALLED_APPS, поскольку это одноэлементный кортеж. Кстати, авторы этой книги предпочитают ставить запятую после каждого элемента кортежа, даже если в нем больше одного элемента. Так уж точно необходимую запятую не забудешь, а за лишнюю не наказывают.

Строка ‘mysite.books’ относится к приложению books, над которым мы работаем. Каждое приложение в списке INSTALLED_APPS представлено полным путем в терминах языка Python, то есть перечнем разделенных точками имен пакетов вплоть до пакета приложения.

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

python manage.py validate

Команда validate проверяет синтаксис и логику моделей. Если все нормально, то появится сообщение 0 errors found (найдено 0 ошибок). В противном случае проверьте правильность написания кода. В сообщении об ошибке приведена информация, помогающая понять, что не так.

Всякий раз при возникновении подозрений относительно моделей выполняйте команду python manage.py validate. Она обнаруживает все типичные ошибки в моделях.

Если модели правильны, выполните показанную ниже команду, которая сгенерирует инструкции CREATE TABLE для моделей из приложения books (при работе в UNIX вы даже получите цветовое выделение синтаксиса):

python manage.py sqlall books

Здесь books – имя приложения, которое было задано при выполнении команды manage.py startapp. В результате вы должны увидеть примерно такой текст:

BEGIN;

CREATE TABLE “books_publisher” ( “id” serial NOT NULL PRIMARY KEY, “name” varchar(30) NOT NULL, “address” varchar(50) NOT NULL, “city” varchar(60) NOT NULL,

“state_province” varchar(30) NOT NULL, “country” varchar(50) NOT NULL, “website” varchar(200) NOT NULL

)

;

CREATE TABLE “books_author” (

“id” serial NOT NULL PRIMARY KEY, “first_name” varchar(30) NOT NULL,

Установка модели

107

“last_name” varchar(40) NOT NULL, “email” varchar(75) NOT NULL

)

;

CREATE TABLE “books_book” (

“id” serial NOT NULL PRIMARY KEY, “title” varchar(100) NOT NULL,

“publisher_id” integer NOT NULL REFERENCES “books_publisher” (“id”) DEFERRABLE INITIALLY DEFERRED,

“publication_date” date NOT NULL

)

;

CREATE TABLE “books_book_authors” ( “id” serial NOT NULL PRIMARY KEY,

“book_id” integer NOT NULL REFERENCES “books_book” (“id”) DEFERRABLE INITIALLY DEFERRED,

“author_id” integer NOT NULL REFERENCES “books_author” (“id”) DEFERRABLE INITIALLY DEFERRED,

UNIQUE (“book_id”, “author_id”)

)

;

CREATE INDEX “books_book_publisher_id” ON “books_book” (“publisher_id”); COMMIT;

Обратите внимание на следующие моменты:

•• Автоматически сгенерированные имена таблиц образуются путем объединения имени приложения (books) с именем модели, записанным строчными буквами (Publisher, Book и Author). Это поведение можно изменить, как описано в приложении B.

•• Как уже отмечалось, Django автоматически добавляет в каждую таблицу первичный ключ – поле id. Это поведение тоже можно переопределить.

•• По принятому соглашению Django добавляет суффикс “_id” к имени внешнего ключа. Как вы, наверное, уже догадались, и это поведение можно переопределить.

•• Ограничение внешнего ключа явно задано фразой REFERENCES.

•• Синтаксис команд CREATE TABLE соответствует используемой СУБД, поэтому зависящие от СУБД свойства полей, например, auto_increment (MySQL), serial (PostgreSQL) или integer primary key (SQLite), устанавливаются автоматически. Это относится и к кавычкам, в которые заключены имена столбцов (одиночные или двойные). В приведенном выше примере использован синтаксис СУБД PostgreSQL.

Команда sqlall не создает никаких таблиц и вообще не обращается к базе данных, она просто выводит на экран команды, которые Django выполнит, если вы попросите. При желании вы можете скопировать эти команды в SQL-клиент для своей СУБД или с помощью конвейера

108

Глава 5. Модели

UNIX передать их клиенту напрямую (например, python manage.py sqlall books | psql mydb). Однако Django предлагает и более простой способ внести изменения в базу данных – команду syncdb:

python manage.py syncdb

Запустив эту команду, вы увидите примерно такой текст:

Creating table books_publisher

Creating table books_author

Creating table books_book

Installing index for books.Book model

Команда syncdb синхронизирует модели с базой данных. Для каждой модели в каждом приложении, указанном в параметре INSTALLED_APPS, она проверит наличие соответствующей таблицы в базе данных и, если нет, создаст ее. Отметим, что syncdb не синхронизирует ни изменения

в моделях, ни удаление моделей; если вы измените или удалите модель,

апотом запустите syncdb, то она ничего не сделает. (Мы еще вернемся к этому вопросу в разделе «Изменение схемы базы данных» в конце этой главы.)

Если еще раз запустить команду python manage.py syncdb, то ничего не произойдет, потому что вы не добавили новые модели в приложение books и не зарегистрировали новые приложения в списке INSTALLED_APPS. Следовательно, команда python manage.py syncdb безопасна, ее запуск ничего не испортит.

Если интересно, подключитесь к серверу с помощью клиента командной строки и посмотрите, какие таблицы создал Django. Клиент можно запустить вручную (например, psql в случае PostgreSQL) или с помощью команды python manage.py dbshell, которая знает, какой клиент запускать в зависимости от параметра DATABASE_SERVER. Почти всегда второй вариант удобнее.

Простой доступ к данным

Django предоставляет высокоуровневый API для работы с моделями на языке Python. Чтобы познакомиться с ним, выполните команду python manage.py shell и введите показанный ниже код:

>>>from books.models import Publisher

>>>p1 = Publisher(name=’Apress’, address=’2855 Telegraph Avenue’,

... city=’Berkeley’, state_province=’CA’, country=’U.S.A.’,

... website=’http://www.apress.com/’)

>>>p1.save()

>>>p2 = Publisher(name=”O’Reilly”, address=’10 Fawcett St.’,

... city=’Cambridge’, state_province=’MA’, country=’U.S.A.’,

... website=’http://www.oreilly.com/’)

>>> p2.save()

Добавление строковых представлений моделей

109

>>>publisher_list = Publisher.objects.all()

>>>publisher_list

[<Publisher: Publisher object>, <Publisher: Publisher object>]

Строчек немного, но в результате происходят интересные вещи. Рассмотрим их более пристально.

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

•• Затем создается объект Publisher, который инициализируется значениями всех полей: name, address и т. д.

•• Чтобы сохранить объект в базе данных, вызывается его метод save(). При этом Django выполняет SQL-команду INSERT.

•• Для выборки издательств из базы данных используется атрибут Publisher.objects, который можно представлять себе как множество всех издательств. Метод Publisher.objects.all() выбирает все объекты Publisher из базы данных. За кулисами Django выполняет SQLкоманду SELECT.

На всякий случай подчеркнем, что Django не сохраняет созданный объект модели в базе данных, пока не будет вызван его метод save().

p1 = Publisher(...)

#В этот момент объект p1 еще не сохранен в базе данных! p1.save()

#А теперь сохранен.

Чтобы создать и сохранить объект за одно действие, используйте метод create(). Следующий пример делает то же самое, что предыдущий:

>>>p1 = Publisher.objects.create(name=’Apress’,

... address=’2855 Telegraph Avenue’,

... city=’Berkeley’, state_province=’CA’, country=’U.S.A.’,

... website=’http://www.apress.com/’)

>>>p2 = Publisher.objects.create(name=”O’Reilly”,

... address=’10 Fawcett St.’, city=’Cambridge’,

... state_province=’MA’, country=’U.S.A.’,

... website=’http://www.oreilly.com/’)

>>>publisher_list = Publisher.objects.all()

>>>publisher_list

Понятно, что предлагаемый Django API доступа к базе данных позволяет сделать многое, но сначала позаботимся об одной мелкой детали.

Добавление строковых представлений моделей

При выводе списка издательств мы получили бесполезную информацию, которая не позволяет отличить один объект Publisher от другого:

[<Publisher: Publisher object>, <Publisher: Publisher object>]

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]