Журнал LinuxFormat - перейти на главную

LXF105:Django

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(викификация, оформление, иллюстрация)
 
м
Строка 280: Строка 280:
 
номера строк приведены исключительно для удобства):
 
номера строк приведены исключительно для удобства):
  
<source lang=python>
+
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
  1 from datetime import datetime
+
from datetime import datetime
  2 from django.template.loader import get_template
+
from django.template.loader import get_template
  3 from django.http import HttpResponse
+
from django.http import HttpResponse
  4 from django.template import RequestContext
+
from django.template import RequestContext
  5
+
 
  6 from news.models import News
+
from news.models import News
  7
+
 
  8 def last_news(request):
+
def last_news(request):
  9 news = News.objects.filter(
+
news = News.objects.filter(
10     pub_date__lte=datetime.now()).order_by(«-pub_date»)[:10]
+
     pub_date__lte=datetime.now()).order_by(«-pub_date»)[:10]
11 template = get_template(“news/last_news.html”)
+
template = get_template(“news/last_news.html”)
12 context = RequestContext(request, {
+
context = RequestContext(request, {
13     “last_news”:news,
+
     “last_news”:news,
14 })
+
})
15 return HttpResponse(template.render(context))
+
return HttpResponse(template.render(context))
 
</source>
 
</source>
  
Строка 365: Строка 365:
  
 
Сам файл '''last_news.html''' может иметь следующий вид:
 
Сам файл '''last_news.html''' может иметь следующий вид:
 +
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 +
{% extends “index.html” %}
  
  1{% extends “index.html” %}
+
{% block application %}
  2
+
{% for news in last_news %}
  3{% block application %}
+
<nowiki>[{{ news.pub_date|date:»d.m.Y»}}]</nowiki>
  4{% for news in last_news %}
+
<nowiki><strong>{{ news.title }}</strong></nowiki>
  5 <nowiki>[{{ news.pub_date|date:»d.m.Y»}}]</nowiki>
+
<nowiki><p>{{ news.description }}</p></nowiki>
  6 <nowiki><strong>{{ news.title }}</strong></nowiki>
+
{% endfor %}
  7 <nowiki><p>{{ news.description }}</p></nowiki>
+
  8{% endfor %}
+
  9
+
10{% endblock %}
+
  
 +
{% endblock %}
 +
</source>
 
Первая строка означает, что шаблон новости расширяет шаблон '''index.html'''. В строке 3 мы открываем блок '''application''' (он, как вы помните,
 
Первая строка означает, что шаблон новости расширяет шаблон '''index.html'''. В строке 3 мы открываем блок '''application''' (он, как вы помните,
 
идет из '''index.html''') и переопределяем его. В строках 5–8 мы создаем цикл
 
идет из '''index.html''') и переопределяем его. В строках 5–8 мы создаем цикл

Версия 19:59, 21 июня 2009

Новая серия! Разрабатываем динамические web-приложения современным способом

Содержание

Django: Новостной портал

ЧАСТЬ 1 Нужен ли миру еще один новостной портал? Вряд ли больше, чем очередной интернет-магазин, но кого это останавливало! Никита Шультайс расскажет эту старую историю на новый лад.

Сегодня каждый более-менее продвинутый пользователь желает иметь свой сайт. Одни устанавливают готовые системы управления 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, хранящее номер новости, к которой относится комментарий.

Теперь, когда модели созданы, приложение можно установить. Этот процесс проходит в два этапа:

  1. Инициализация приложения в settings.py в разделе INSTALLED_APPS;
  2. Создание таблиц в базе данных.

Откройте settngs.py и добавьте к INSTALLED_APPS строку 'myproject.news'. Заметьте, что INSTALLED_APPS – это кортеж Python, поэтому будьте внимательны с синтаксисом. Теперь перейдите в корень нашего проекта и наберите команду:

 python manage.py syncdb

Она, как мы уже знаем, создаст необходимые таблицы в БД.

Автогенерация «админки»

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

Для того, чтобы подключить систему администрирования, нужно выполнить несколько шагов (в той очередности, в которой они представлены ниже):

  1. Добавить django.contrib.admin в INSTALLED_APPS вашего проекта.
  2. Выполнить python manage.py syncdb из корневого каталога проекта.
  3. Открыть 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. Затем добавьте следующий код (разумеется, номера строк приведены исключительно для удобства):

  1. from datetime import datetime
  2. from django.template.loader import get_template
  3. from django.http import HttpResponse
  4. from django.template import RequestContext
  5.  
  6. from news.models import News
  7.  
  8. def last_news(request):
  9. news = News.objects.filter(
  10.      pub_date__lte=datetime.now()).order_by(«-pub_date»)[:10]
  11. template = get_template(“news/last_news.html)
  12. context = RequestContext(request, {
  13.      “last_news”:news,
  14. })
  15. 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.


Теперь, когда базовый шаблон готов, перейдем к шаблону новостей. Опять же, создадим в директории нашего приложения (news) каталог templates, внутри templates создадим каталог news, а в templates/news добавим файл last_news.html. Заметьте, что имя файла шаблона совпадает с именем представления, к которому оно относится. Так делать не обязательно – это просто правило хорошего стиля.

Сам файл last_news.html может иметь следующий вид:

  1. {% extends “index.html%}
  2.  
  3. {% block application %}
  4. {% for news in last_news %}
  5.  <nowiki>[{{ news.pub_date|date:»d.m.Y»}}]</nowiki>
  6.  <nowiki><strong>{{ news.title }}</strong></nowiki>
  7.  <nowiki><p>{{ news.description }}</p></nowiki>
  8. {% endfor %}
  9.  
  10. {% 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

Персональные инструменты
купить
подписаться
Яндекс.Метрика