- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF105:Django
Материал из Linuxformat.
- Новая серия! Разрабатываем динамические web-приложения современным способом
Содержание |
Django: Новостной портал
Django |
---|
|
- ЧАСТЬ 1 Нужен ли миру еще один новостной портал? Вряд ли больше, чем очередной интернет-магазин, но кого это останавливало! Никита Шультайс (http://shultais.ru) расскажет эту старую историю на новый лад.
Сегодня каждый более-менее продвинутый пользователь желает иметь свой сайт. Одни устанавливают готовые системы управления web-содержимым (CMS), вторые пишут все с нуля, а третьи – используют web-каркасы (framework), позволяющие создавать отличные динамические web-сайты без особых усилий. Django как раз и является таким каркасом, написанным на Python. К числу задач, с которыми он помогает справиться, относятся:
- Создание и обработка форм;
- Разделение логики и представления с помощью мощной системы шаблонов;
- Добавление, поиск, извлечение и удаление записей из базы данных, в объектно-ориентированном стиле (ORM);
- Обработка URL с помощью регулярных выражений;
- Автогенерация интерфейса администратора (в просторечии, «админки»);
- Аутентификация и авторизация пользователей;
- Кэширование как отдельных элементов, так и целых страниц;
- Интернационализация сайта;
- Создание и отправка сообщений по e-mail;
- Тестирование;
- Работа с сессиям, HTTP-запросами и cookie.
Все эти возможности сочетаются с относительно высокой скоростью работы и простотой написания кода. Ну что, заинтересовались? Тогда приступим.
На исходную!
Дистрибутив Django можно скачать с официального сайта (http://www.djangoproject.com) или взять с LXFDVD. Желательно использовать версию из репозитория (0.97), но можно ограничиться и последним стабильным релизом – 0.96. Кроме того, для связи с сервером MySQL нам понадобится MySQLdb версии 1.2.1p2 или выше. После получения Django, распакуйте архив, перейдите в появившийся каталог и выполните
sudo python setup.py install [ваш пароль]
При желании, можете заменить sudo на su и ввести пароль суперпользователя.
Для начала работы нам нужно создать «проект», в котором будут храниться все наши файлы. Для этого перейдите в директорию, в которой вы собираетесь хранить проект (например, /var/www), и дайте команду
python /путь/к/django/bin/django-admin.py startproject myproject
после выполнения которой в текущем каталоге появится поддиректория с именем myproject.
Рассмотрим ее внутреннюю структуру:
myproject/ __init__.py manage.py settings.py urls.py
__init__.py – это специальный (как видно по двум подчеркиваниям в имени) файл, который указывает на то, что данный каталог является модулем (пакетом) языка Python; manage.py – утилита, позволяющая управлять вашим проектом. Settings.py содержит его настройки, а urls.py – это так называемый «файл URL-карт». В нем указывается, какому адресу какой код соответствует.
Для запуска проекта выполните из его директории команду
python manage.py runserver
Она запустит встроенный в Django web-сервер, предназначенный специально для разработки сайтов. Сервер стартует на локальном хосте на порту 8000 и, если все пройдет успешно, вы увидите в консоли следующее сообщение:
Validating models... 0 errors found. Django version 1.0, using settings 'myproject.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
Направив свой любимый web-браузер по адресу http://127.0.0.1:8000/:, вы получите нечто похожее на рис. 1.
Настроим Django
Как уже говорилось выше, основные настройки вашего проекта хранятся в файле settings.py. Откроем его и найдем строку DATABASE_ENGINE = : она отвечает за СУБД, которую мы будем использовать в нашем проекте. Поскольку мы выбрали MySQL, изменим эту строку на DATABASE_ENGINE = 'mysql'. Далее, в DATABASE_USER укажем имя пользователя вашей базы данных (заметьте, что у него должны быть права на создание таблиц в БД), а в DATABASE_PASSWORD – его пароль. Если сервер баз данных запущен на локальном хосте и на порту по умолчанию, параметры DATABASE_HOST и DATABASE_PORT можно оставить пустыми. В поле DATABASE_NAME введите имя базы данных (не путайте его с именем СУБД!), которую будет использовать проект. Да, и не забудьте создать ее перед использованием. В частности, для MySQL это делается так:
mysql --user=username --password=password mysql > CREATE DATABASE `myproject_base` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Здесь username – имя пользователя, который имеет доступ к СУБД, password – его пароль, myproject_base – название БД, в которой будут храниться данные нашего проекта.
Перейдем к секции INSTALLED_APPS, которая отвечает за установленные в нашем проекте приложения. По умолчанию, команда startproject создает проект с четырьмя предустановленными приложениями общего назначения:
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', )
Каждое из них отвечает за свою специфическую область:
- django.contrib.auth – система аутентификации;
- django.contrib.contenttypes – каркас типов содержимого;
- django.contrib.sessions – работа с сессиями;
- django.contrib.sites – каркас, позволяющий управлять несколькими сайтами из одной установки Django.
Хотя эти приложения и перечислены в INSTALLED_APPS, они еще не установлены окончательно, так как для них не созданы таблицы в базе данных. Для завершения инсталляции, выполните следующий код:
python manage.py syncdb
Данная команда создаст необходимые таблицы в базе данных, после чего вам будет предложено определить суперпользователя – администратора сайта:
You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no):
Ответьте «yes», а затем следуйте инструкциям, заполняя поля имени, e-mail и пароля для суперпользователя. Вот теперь система полностью установлена.
Создание приложения
Перечисленные выше приложения Django – это, по сути, программы Python, предназначенные для решения конкретной задачи. Например, мы можем написать приложение-блог, которое будет создавать записи в личном интернет-дневнике, а также предоставлять другим пользователям возможность просматривать их. Для генерации нового приложения нужно просто скомандовать:
python manage.py startapp news
где news – имя нашего приложения; его-то мы и будем разрабатывать на протяжении всех четырех уроков. Задача news достаточно стандартна: это публикация, просмотр и обсуждение новостей. По традиции, давайте начнем с изучения структуры нашего приложения:
news/ __init__.py models.py views.py
Как видно, оно состоит из трех файлов: __init__.py, с которым мы уже встречались выше, models.py – места для описания моделей (схем таблиц в БД с некоторыми дополнительными данными) и views.py, определяющего представления (код, который отвечает за логику вашего приложения).
Работа с приложением обычно начинается с создания моделей, поэтому откройте файл models.py в вашем любимом текстовом редакторе и наберите следующий код:
from django.db import models class News(models.Model): title = models.CharField(max_length=70) description = models.CharField(max_length=255) pub_date = models.DateTimeField() text = models.TextField() class Comment(models.Model): news = models.ForeignKey(News) username = models.CharField(max_length=70) text = models.TextField() pub_date = models.DateTimeField(auto_now_add=True)
Мы создали две модели: первая (News) отвечает за саму новость, а вторая (Comment) – за комментарии к ней.
Каждая модель (таблица, в терминах БД) представлена классом, который наследуется от django.db.models.Model. Все поля представляются объектом класса models.*Field. Имя поля используется как для создания столбцов в таблице БД, так и для доступа к данным через Django ORM, поэтому для упрощения чтения и написания кода старайтесь давать полям осмысленные названия.
Начнем с поля title класса News. Запись models.CharField указывает на то, что это поле является символьным, а max_length=70 говорит, что мы можем записать в него максимум 70 символов. Соответственно, DateTimeField означает, что поле будет содержать дату в формате DateTime (атрибут auto_now_add в pub_date в классе Comments указывает на то, что поле при создании записи будет автоматически заполняться текущим временем), TextField – это обычный текст.
Особое значение имеет ForeignKey, который говорит, что поле является внешним ключом (в связке «один-ко-многим») по отношению к модели (таблице) News. То есть, у каждого комментария есть поле news, хранящее номер новости, к которой относится комментарий.
Теперь, когда модели созданы, приложение можно установить. Этот процесс проходит в два этапа:
- Инициализация приложения в settings.py в разделе INSTALLED_APPS;
- Создание таблиц в базе данных.
Откройте settngs.py и добавьте к INSTALLED_APPS строку 'myproject.news'. Заметьте, что INSTALLED_APPS – это кортеж Python, поэтому будьте внимательны с синтаксисом. Теперь перейдите в корень нашего проекта и наберите команду:
python manage.py syncdb
Она, как мы уже знаем, создаст необходимые таблицы в БД.
Автогенерация «админки»
Одной из замечательных возможностей Django является автогенерация раздела администрирования сайта. Конечно, в серьезных работающих проектах его использование не вполне удобно, однако на стадии разработки и в небольших проектах он очень полезен.
Для того, чтобы подключить систему администрирования, нужно выполнить несколько шагов (в той очередности, в которой они представлены ниже):
- Добавить django.contrib.admin в INSTALLED_APPS вашего проекта.
- Выполнить python manage.py syncdb из корневого каталога проекта.
- Открыть myproject/urls.py и раскомментировать строку
# (r'^admin/', include('django.contrib.admin.urls')),
После этого запустите web-сервер (python manage.py runserver) и перейдите по адресу http://127.0.0.1:8000/admin/. Вы увидите форму авторизации для входа в систему администрирования:
Введите имя и пароль суперпользователя, и – добро пожаловать в «админку» Django! На ее главной странице (рис.3) можно видеть несколько областей:
- Вверху – панель приветствия, просмотра документации, изменения пароля и выхода из системы.
- Посередине слева – установленные приложения (название и модели) и действия, которые можно совершать с ними (добавление и изменение записей).
- Посередине справа – последние действия, которые были произведены в «админке».
Вы заметили, что нашего приложения news в нет списке (в журнале этого не видно, но уж поверьте мне на слово)? Все правильно: просто так приложения в нем не появляются – для этого нужно выполнить несколько несложных действий. Откройте файл моделей (models.py) приложения news и добавьте в каждую модель подкласс.
class Admin: pass
Сохраните файл моделей и перезагрузите страницу. Теперь наше приложение должно быть доступно в «админке». Если бы мы использовали какой-то другой HTTP-сервер (например, Apache), нам бы пришлось бы перегружать его после каждого изменения в исходных кодах. А это очень неудобно, особенно когда процесс разработки в самом разгаре.
Ну что, добавим первую новость? Найдите на странице строку Newss (это не опечатка – Django автоматически добавляет окончание -s к именам моделей) и перейдите по ссылке Add. Откроется форма для добавления новости:
Заполните все поля и нажмите кнопку Save [Сохранить]. Вы будете перенаправлены на страницу списка доступных новостей. Пока что он состоит из одной новости, которую мы только что добавили, но как только их станет больше, возникнет одно неудобство: все новости будут отображаться как News object [Объект класса News], и мы быстро запутаемся, где какая. Чтобы видеть заголовок новости, изменим models.py приложения news, добавив в модель News следующий код:
def __unicode__(self): return self.title
Обновите страницу – у новостей появятся осмысленные названия. Давайте добавим еще одну новость, но на этот раз оставим поле Title пустым, в поле Date напишем слово «дата», а в поле Time – «время» и попробуем сохранить ее в базе. Что, Django ругается? И правильно делает – нечего оставлять поля пустыми. Обратите внимание, что прочие поля (которые были введены верно) остались нетронутыми, и вам осталось только исправить ошибки, а не заполнять форму заново, как это часто бывает на сайтах «средней руки».
Публикация в сети
Хорошо, создавать записи («объекты» в терминах Django ORM) мы научились, а дальше-то что? Дальше нам надо разместить их на сайте – ведь от новостей, которые никто не видит, нет пользы. Чтобы сделать это, нужно опять пройти через несколько несложных этапов:
- Создать представление (функцию, отвечающую за логику), которое будет выбирать нужные нам объекты из базы данных и обрабатывать их в соответствии с нашими потребностями;
- Создать шаблон, который будет отвечать за стиль отображения данных;
- Передать выбранные объекты в шаблон;
- Связать URL с нашим представлением.
Порядок тут особой роли не играет. К тому же, за разные действия могут отвечать разные люди: за представления – программист, за шаблоны – дизайнер.
Начнем с представлений. Они, как мы знаем, хранятся в файле views.py в корне каждого приложения. Перейдите в директорию news и откройте файл views.py. Затем добавьте следующий код (разумеется, номера строк приведены исключительно для удобства):
- from datetime import datetime
- from django.template.loader import get_template
- from django.http import HttpResponse
- from django.template import RequestContext
- from news.models import News
- def last_news(request):
- news = News.objects.filter(
- pub_date__lte=datetime.now()).order_by("-pub_date")[:10]
- template = get_template("news/last_news.html")
- context = RequestContext(request, {
- "last_news":news,
- })
- return HttpResponse(template.render(context))
Первые четыре строчки загружают необходимые функции и классы:
- datetime – тип для работы с датой и временем;
- get_template – функция, которая ищет и возвращает шаблон;
- HttpResponse – основной HTTP ответ;
- RequestContext – специальный класс, с помощью которого можно определять переменные, используемые в шаблонах.
Далее (строка 6) происходит импорт класса модели наших новостей. С его помощью мы получаем доступ к Django ORM, и, следовательно, к объектам в нашей базе данных.
Функция last_news – это и есть представление. Заметьте, что она принимает обязательный аргумент request, через который передаются параметры HTTP-запроса.
Что же происходит при вызове last_news? Сначала мы извлекаем объекты из базы данных (строки 9–10). Конструкция filter ограничивает выборку по какому-то условию, в нашем случае pub_date__lte=datetime.now() означает, что дата публикации новостей должна быть меньше или равна (lte – «less than or equal to») текущей дате (datetime.now()). Это позволит нам создавать новости «на будущее», и они не будут отображаться на сайте до тех пор, пока дата их публикации не станет раньше или равной текущей. order_by – сортирует записи по определенному столбцу, в нашем случае – pub_date, а знак минус означает, что сортировка будет произведена в обратном порядке. И наконец [:10] – срез, который указывает, что извлекать нужно только 10 последних записей.
В строке 11 мы получаем объект шаблона, передавая в функцию get_template путь до него. Строки 12–14 отвечают за наполнение наших шаблонов какими-то данными, причем мы передаем в шаблон весь HTTP- запрос (request) и извлеченные новости (на самом деле, они еще даже не извлечены: просто создан объект, с помощью которого новости будут получены при первом обращении к ним). Обратите внимание, что данные передаются в шаблон с помощью словаря, где ключ – это имя переменной, которая будет доступна в шаблоне, а значение – ее значение.
Ну и, наконец, в последней строке мы возвращаем стандартный HTTP- ответ, в который передаем готовый заполненный шаблон. Вот только... где взять шаблон?
Шаблоны
Для начала подготовим базовый шаблон – index.html. Создадим в корне нашего проекта каталог media для хранения статичных файлов (изображений, шаблонов, стилей и т.д.), а уже в media – подкаталог templates, в который и поместим файл index.html со следующим содержимым:
<html> <head><title>My site</title></head> <body> <a href="/news/">News</a><br/> {% block application %} Welcome to site. {% endblock %} </body> </html>
Шаблон – это обычный текстовый файл, содержащий специальные конструкции языка шаблонов Django. В index.html содержится только одна конструкция, которая определяет блок application (строки 6-8). Она называется «тэгом», причем тэг начинается с {%, а заканчивается %}. Внутри этого блока находится приветствие, как это часто бывает на сайтах. Django еще не знает, где искать шаблон, поэтому откроем settings.py, найдем кортеж TEMPLATE_DIRS и добавим в него строку /path/to/project/myproject/media/templates/, где /path/to/project – путь до вашего проекта; у меня это /var/www.
Если вы не увидели ни одной новости (при условии, что они были добавлены), то скорее всего, вы не попали в нужный часовой пояс. Когда мы вызываем функцию datetime.now(), она возвращает время относительно часового пояса, заданного в переменной TIME_ZONE в файле settings.py. По умолчанию в нем содержится America/Chicago. Все, что вам нужно – это изменить значение на название вашего часового пояса на английском, например, на Asia/Krasnoyarsk. Cписок часовых поясов можно найти в директории /usr/share/zoneinfo/ в файле zone.tab.
Теперь, когда базовый шаблон готов, перейдем к шаблону новостей. Опять же, создадим в директории нашего приложения (news) каталог templates, внутри templates создадим каталог news, а в templates/news добавим файл last_news.html. Заметьте, что имя файла шаблона совпадает с именем представления, к которому оно относится. Так делать не обязательно – это просто правило хорошего стиля.
Сам файл last_news.html может иметь следующий вид:
- {% extends "index.html" %}
- {% block application %}
- {% for news in last_news %}
- [{{ news.pub_date|date:"d.m.Y"}}]
- <strong>{{ news.title }}</strong>
- <p>{{ news.description }}</p>
- {% endfor %}
- {% endblock %}
Первая строка означает, что шаблон новости расширяет шаблон index.html. В строке 3 мы открываем блок application (он, как вы помните, идет из index.html) и переопределяем его. В строках 5–8 мы создаем цикл по объектам last_news (которые были переданы в шаблон из нашего представления). В строках 6–8 мы вставляем данные, относящиеся к каждой новости, из last_news. Помимо тэгов, в шаблоны можно помещать переменные, имена которых будут заменены их значениями. Для этого используется конструкция {{ имя_переменной }}. В строке 7 мы обращаемся к переменной news, но каждая новость имеет несколько полей (в соответствии с тем, что мы определили в models.py), поэтому мы указываем конкретное поле – title, что в конечном счете выведет заголовок новости. Особое внимание нужно обратить на запись в строке 6, где мы не просто обращаемся к дате публикации новости news.pub_date, но и применяем фильтр форматирования |date:«d.m.Y», который позволяет вывести дату в более традиционном для России виде.
Последнее, что нам осталось – это связать URL с представлением. Откроем urls.py и после строки
(r'^admin/', include('django.contrib.admin.urls')),
добавим
(r'^news/', 'news.views.last_news').
Данный код означает, что при переходе к http://www.mydomain.ru/news/ будет выполняться представление news.views.last_news.
Затем допишите в самый конец файла
urlpatterns += patterns('django.views.generic.simple', (r'^$','direct_to_template', {'template': 'index.html'}),)
Эта запись говорит, что при обращении к корню сервера должен использоваться шаблон index.html.
Ну все, наш сайт готов. Запустите сервер разработчика и перейдите в вашем браузере по адресу http://127.0.0.1:8000/. Кликните по ссылке News и получите самые свежие новости! LXF