<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Steve</id>
		<title>Linuxformat - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Steve"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/Steve"/>
		<updated>2026-05-13T11:08:06Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF108:Django</id>
		<title>LXF108:Django</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF108:Django"/>
				<updated>2010-12-01T14:24:20Z</updated>
		
		<summary type="html">&lt;p&gt;Steve: /* Финальные штрихи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Django}}&lt;br /&gt;
== Финальные штрихи ==&lt;br /&gt;
: ''ЧАСТЬ 4 Уроки Django подходят к концу, наступает пора экзаменов – если не для вас, то для приложений уж точно. '''Никита Шультайс''' (http://shultais.ru) разберется с тестированием и пробежится по другим возможностям этого каркаса.''&lt;br /&gt;
&lt;br /&gt;
Новостная лента готова – но оправдает ли она ожидания&lt;br /&gt;
пользователей? Ответ на этот вопрос может дать тестирование, лучше всего – в реальных условиях; но какие-то&lt;br /&gt;
основные вещи можно проверить еще на этапе разработки [http://www.thesiswritingservice.com/ thesis writers]. Если вы&lt;br /&gt;
успели заглянуть в учебник [[LXF108:Rails|Rails]], то уже знаете о методологии TDD. Мы, однако, пойдем другим путем, и будем тестировать&lt;br /&gt;
приложение не до написания, а после.&lt;br /&gt;
&lt;br /&gt;
Дело это – серьезное и сложное, так как нам нужно учитывать&lt;br /&gt;
взаимодействие с БД, компиляцию шаблонов, обработку GET- и&lt;br /&gt;
POST-запросов и прочие компоненты системы: сбой в любом из&lt;br /&gt;
них может вызвать нарушить работу всего сайта. К данной задаче&lt;br /&gt;
можно подойти с двух сторон:&lt;br /&gt;
* Тестирование в браузере. Речь идет о программах Twill (http://twill.idyll.org) и Selenium (http://selenium.openqa.org): они «запоминают» последовательность ваших действий для каждой страницы, а затем воспроизводят ее по запросу. Например, можно ввести в поля формы заведомо неверные данные, получить ожидаемую ошибку и повторять этот тест при каждом серьезном изменении в коде вашего приложения.&lt;br /&gt;
* Тестирование на сервере. И тут Django не оставляет нас на произвол судьбы, предлагая сразу два варианта: doctest (тестирование через документацию) и unittest (модульное тестирование), плюс специальный клиент для отправки GET- и POST-запросов.&lt;br /&gt;
&lt;br /&gt;
Если вы давно программируете на Python, то вам, наверное,&lt;br /&gt;
будет ближе doctest, а мигрантам из мира Java скорее придется по&lt;br /&gt;
вкусу unittest. Никаких ограничений на их использование не накладывается: вы можете выбрать одну систему или применять обе сразу. Мы же остановимся на doctest.&lt;br /&gt;
&lt;br /&gt;
=== Документируй это! ===&lt;br /&gt;
Строка документации в Python – это обычный текст, размещаемый&lt;br /&gt;
после определения функции или класса непосредственно в исходном&lt;br /&gt;
коде. Она же предоставляет содержимое для атрибута __doc__. Как&lt;br /&gt;
правило, ее помещают в тройные кавычки (&amp;quot;&amp;quot;&amp;quot;), что позволяет вводить&lt;br /&gt;
сложные конструкции с переносами строк, отступами, теми же кавычками и... тестами. Этим мы и воспользуемся.&lt;br /&gt;
&lt;br /&gt;
Тесты могут находится в файлах моделей (models.py) – для проверки последних – и в специальных файлах tests.py, расположенных&lt;br /&gt;
в директории приложения. К примеру, создайте файл news/tests.py&lt;br /&gt;
такого содержания:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from news.models import News&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from datetime import datetime&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; news = News(title=&amp;quot;Заголовок&amp;quot;,description=&amp;quot;Описание&amp;quot;,pub_date=datetime.now(), text=&amp;quot;Текст&amp;quot;)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; news.save()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; news = News.objects.get(pk=1)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print news.title.encode('utf-8')&lt;br /&gt;
 Заголовок&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В строке 1 задается кодировка, а начиная с третьей идет сам&lt;br /&gt;
тест. Заметьте, что каждая строка начинается с трех знаков «больше» (&amp;gt;&amp;gt;&amp;gt;), как в интерактивном режиме работы Python. В строке 10&lt;br /&gt;
этих знаков нет, так как она содержит ожидаемый вывод команды&lt;br /&gt;
print со строки 9.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF108 85 1.png|thumb|200px|Рис. 1. Тест пройден удачно!]]&lt;br /&gt;
Перед тем, как запустить тест, в settings.py нужно добавить&lt;br /&gt;
строку&lt;br /&gt;
 TEST_DATABASE_CHARSET=&amp;quot;UTF8&amp;quot;&lt;br /&gt;
чтобы кодировки файла и базы данных совпадали. Перед выполнением теста Django создаст специальную вспомогательную БД, поэтому&lt;br /&gt;
пользователь, указанный в settings.DATABASE_USER, должен иметь&lt;br /&gt;
соответствующие права. Для начала тестирования введите команду:&lt;br /&gt;
 python manage.py test news&lt;br /&gt;
после выполнения которой вы увидите примерно то, что показано&lt;br /&gt;
на рис. 1.&lt;br /&gt;
&lt;br /&gt;
Сообщения похожи на появляющиеся во время создания таблиц&lt;br /&gt;
при первой установке, но теперь все происходит в тестовой БД. В&lt;br /&gt;
конце отображается число выполненных тестов, их результаты и&lt;br /&gt;
уведомление об уничтожении тестовой базы. Мы проверяли наше&lt;br /&gt;
приложение (news), но, как вы помните, Django содержит несколько&lt;br /&gt;
собственных приложений и представлений (например, «админку») –&lt;br /&gt;
и они тоже снабжаются своими тестами. Чтобы выполнить их все,&lt;br /&gt;
нужно ввести команду:&lt;br /&gt;
 python manage.py test&lt;br /&gt;
добавив предварительно в главный файл URL-карт следующие&lt;br /&gt;
строки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;urlpatterns += patterns('django.contrib.auth.views',&lt;br /&gt;
url(r'^auth/password_reset/$','password_reset'),&lt;br /&gt;
)&amp;lt;/source&amp;gt;&lt;br /&gt;
Здесь мы подключаем одно из встроенных представлений, предназначенное для восстановления пароля. Это необходимо, так как при&lt;br /&gt;
тестировании всего проекта происходит обращение по указанному URL,&lt;br /&gt;
и если представление не определено, тест будет провален. Кстати, вы&lt;br /&gt;
тоже можете попробовать password_reset в работе (рис. 2).&lt;br /&gt;
[[Изображение:LXF108 85 2.png|frame|center|Рис. 2. Забыли пароль? Это проблемы Django!]]&lt;br /&gt;
&lt;br /&gt;
=== Имитатор Сети ===&lt;br /&gt;
Количество тестов уже достигло шести, но помимо создания и&lt;br /&gt;
извлечения объектов из базы, нам нужно проверить реакцию на&lt;br /&gt;
GET- и POST-запросы. Как вы знаете, для этих целей существует&lt;br /&gt;
специальный клиент: он эмулирует запрос и возвращает переменные, которые передаются в шаблон для данного URL. Добавьте в&lt;br /&gt;
файл tests.py после строки 10 следующий код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot; line start=&amp;quot;11&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from django.contrib.auth.models import User&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; user = User.objects.create_user('django_guru', 'user@example.com', 'password')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; user.save()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from django.test.client import Client&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = Client()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c.login(username='django_guru',password=“password”)&lt;br /&gt;
True&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; response = c.get('/news/1/')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; response.status_code&lt;br /&gt;
200&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print response.context[0]['user'].username&lt;br /&gt;
django_guru&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; response = c.post('/news/1/',{'username':“testuser”,'text':»»})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; response.status_code&lt;br /&gt;
200&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; response = c.post('/news/1/',{'username':“testuser”,'text':»Comment text»})&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; response.status_code&lt;br /&gt;
302&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from news.models import Comment&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; comment = Comment.objects.get(news=news)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print comment.text&lt;br /&gt;
Comment text&amp;lt;/source&amp;gt;&lt;br /&gt;
Разберемся, что здесь происходит. В строках 11–13 мы создаем&lt;br /&gt;
нового пользователя (django_guru), а в 14–15 – тестовый клиент. В&lt;br /&gt;
строке 16 django_guru авторизуется, и отныне все действия в системе&lt;br /&gt;
будут совершаться от его имени. В строке 18 мы переходим на страницу нашей первой новости, передав средствами клиента GET-запрос.&lt;br /&gt;
Для проверки, что нам это удалось, мы изучаем код ответа сервера&lt;br /&gt;
(строка 19) – он должен равняться 200, или тест будет провален.&lt;br /&gt;
Затем (строки 21–22), чтением дополнительных данных ответа, мы&lt;br /&gt;
убеждаемся, что запрос сделал зарегистрированный пользователь&lt;br /&gt;
django_guru. Теперь самое время оставить комментарий – не зря же&lt;br /&gt;
мы авторизовались? В строке 23 генерируется POST-запрос (второй&lt;br /&gt;
аргумент метода post() – словарь отсылаемых на сервер данных).&lt;br /&gt;
Обратите внимание, что значение ключа text оставлено пустым, а&lt;br /&gt;
значит, комментарий не добавится, однако сервер по-прежнему должен возвращать код 200 (строка 25). А вот в строке 26 мы передаем&lt;br /&gt;
все необходимые данные, и так как после создания комментария нас&lt;br /&gt;
перенаправляют на страницу новости, код ответа должен быть равен&lt;br /&gt;
302 (Требуемый URL перемещен). В строках 29–32 проверяется, что&lt;br /&gt;
комментарий был действительно добавлен: мы сравниваем его текст&lt;br /&gt;
с исходным значением. Уфф... тест пройден.&lt;br /&gt;
&lt;br /&gt;
=== Действительно простая синдикация ===&lt;br /&gt;
Какой новостной сайт без ленты? RSS и/или Atom есть везде – будут&lt;br /&gt;
и у нас, а Django нам в этом поможет. Откройте главный файл URL-карт и добавьте в его конец следующие строки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
from feeds import LatestNews&lt;br /&gt;
&lt;br /&gt;
feeds = {&lt;br /&gt;
'latest': LatestNews,&lt;br /&gt;
}&lt;br /&gt;
urlpatterns += patterns('',&lt;br /&gt;
(r'^feeds/(?P&amp;lt;url&amp;gt;.*)/$', 'django.contrib.syndication.views.feed',&lt;br /&gt;
{'feed_dict': feeds}),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Далее нужно приготовить ленту LatestNews, которую мы импортируем в строке 1. Создайте в корне проекта каталог feeds с файлом&lt;br /&gt;
__init__.py следующего содержания:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from django.contrib.syndication.feeds import Feed&lt;br /&gt;
from news.models import News&lt;br /&gt;
from django.contrib.syndication.feeds import FeedDoesNotExist&lt;br /&gt;
&lt;br /&gt;
class LatestNews(Feed):&lt;br /&gt;
title = &amp;quot;Последние новости нашего сайта&amp;quot;&lt;br /&gt;
description = &amp;quot;Последние события на сайте mysite.com&amp;quot;&lt;br /&gt;
link = &amp;quot;http://127.0.0.1:8000/news/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def items(self):&lt;br /&gt;
return News.objects.order_by(&amp;quot;-pub_date&amp;quot;)[:5]&lt;br /&gt;
&lt;br /&gt;
def item_link(self, obj):&lt;br /&gt;
from django.core.urlresolvers import reverse&lt;br /&gt;
return 'http://127.0.0.1:8000%s' % reverse('news.news_detail',kwargs={&amp;quot;news_id&amp;quot;:obj.pk})&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[Изображение:LXF108 86 1.png|thumb|250px|Рис. 3. Firefox предлагает подписаться на обновления нашего новостного сайта – теперь держитесь!]]&lt;br /&gt;
Поля title, description и link класса LatestNews являются обязательными и отвечают за одноименные элементы RSS. Метод items()&lt;br /&gt;
передает в ленту требуемые объекты, а item_link() отвечает за ссылку&lt;br /&gt;
на сайт. Теперь создайте каталог feeds в media/templates и добавьте&lt;br /&gt;
в него два файла, latest_description.html и latest_title.html: они будут&lt;br /&gt;
отвечать за вид новостной ленты. В lates_description.html напишите:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{ obj.description }}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
а в latest_title.html:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[{{ obj.pub_date|date:&amp;quot;d.m.Y&amp;quot; }}] {{ obj.title }}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Объект obj представляет собой запись из выборки, которую мы&lt;br /&gt;
возвращаем в строке 13 файла feeds/__init__.py. Пройдя по адресу&lt;br /&gt;
http://127.0.0.1:8000/feeds/latest/, мы увидим предложение Firefox&lt;br /&gt;
сохранить ленту новостей. Пользователи KDE, вероятно, предпочтут&lt;br /&gt;
Akregator – с ним тоже нет никаких проблем (рис. 3, 4)&lt;br /&gt;
&lt;br /&gt;
=== Общие представления ===&lt;br /&gt;
Чтобы облегчить жизнь web-разработчика, Django включил большое&lt;br /&gt;
число представлений для решения стандартных задач. Так, добавив&lt;br /&gt;
в главный файл URL-карт следующий код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from django.views.generic.list_detail import object_list&lt;br /&gt;
from news.models import News&lt;br /&gt;
urlpatterns += patterns('',&lt;br /&gt;
('^lastnews/$', object_list, {&lt;br /&gt;
'queryset': News.objects.all().order_by('-pub_date')[:10],&lt;br /&gt;
'template_name':'news/last_news.html',&lt;br /&gt;
'template_object_name':'last_news'})&lt;br /&gt;
)&amp;lt;/source&amp;gt;&lt;br /&gt;
а также заменив в файле news/templates/news/last_news.html&lt;br /&gt;
 {% for news in last_news %}&lt;br /&gt;
на&lt;br /&gt;
 {% for news in last_news_list %}&lt;br /&gt;
мы сможем просматривать последние новости по адресу&lt;br /&gt;
http://127.0.0.1:8000/lastnews/, не вызывая представление news.last_news. Чтобы сделать доступными оба варианта, нужно найти в представлении news.last_news строку&lt;br /&gt;
 &amp;quot;last_news&amp;quot;:news,&lt;br /&gt;
и заменить ее на&lt;br /&gt;
 &amp;quot;last_news_list&amp;quot;:news,&lt;br /&gt;
Как вы уже догадались, общее представление object_list предназначено для работы со списком объектов. Еще есть представления для&lt;br /&gt;
вывода объектов в зависимости от даты (django.views.generic.date_based.*), что позволяет очень просто создавать архивы записей:&lt;br /&gt;
* archive_index – вывод последних объектов, добавленных в базу данных;&lt;br /&gt;
* archive_{year,month,week,day,today} – вывод всех объектов за определенный год, месяц, неделю, день или за сегодня;&lt;br /&gt;
* object_detail – вывод одного объекта за определенный день.&lt;br /&gt;
Доступны общие представления для создания, обновления и&lt;br /&gt;
удаления объектов. Все они работают немного быстрее, чем созданные вручную, но позволяют решать лишь самые элементарные задачи. Если данные в вашем приложении выбираются из нескольких&lt;br /&gt;
таблиц и это сопровождается расчетами, то общие представления&lt;br /&gt;
не помогут – на то они и общие.&lt;br /&gt;
&lt;br /&gt;
=== Добавляем переменные на лету ===&lt;br /&gt;
В глубинах Django скрываются глобальные контекстные процессоры, основная задача которых – снабжать шаблоны переменными&lt;br /&gt;
и объектами. Узнать, какие из них подключены, можно в кортеже&lt;br /&gt;
TEMPLATE_CONTEXT_PROCESSORS в файле settings.py. Например, у&lt;br /&gt;
нас сейчас работают следующие процессоры:&lt;br /&gt;
* auth – информация о пользователе: объект user, его права доступа и сообщения, которые были ему отправлены;&lt;br /&gt;
* i18n – сведения о текущем языке сайта и клиента;&lt;br /&gt;
* request – данные о запросе.&lt;br /&gt;
Кроме них, существует еще процессор debug, передающий в&lt;br /&gt;
шаблон данные о выполненных SQL-запросах, плюс мы можем&lt;br /&gt;
написать свой собственный! Для этого создадим в корне нашего&lt;br /&gt;
проекта каталог processors и добавим в него два файла: __init__.py&lt;br /&gt;
и context_processors.py. Последний должен содержать такой код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import settings&lt;br /&gt;
def site_settings(request):&lt;br /&gt;
return {'SETTINGS': settings}&amp;lt;/source&amp;gt;&lt;br /&gt;
Чтобы подключить процессор, просто перечислите его в кортеже&lt;br /&gt;
TEMPLATE_CONTEXT_PROCESSORS. Проверим работоспособность:&lt;br /&gt;
добавим в шаблон news.html следующее:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{ SETTINGS.TIME_ZONE }}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Конечно, TIME_ZONE можно заменить на любую другую переменную, определенную в settings.py.&lt;br /&gt;
&lt;br /&gt;
=== Сам себе фильтр ===&lt;br /&gt;
С фильтрами мы познакомились еще в [[LXF105:Django|LXF105]], однако часто возникают ситуации, когда поставляемых с Django вариантов недостаточно. Чтобы написать свой собственный фильтр, создайте в корне&lt;br /&gt;
проекта каталог templatetags/ и добавьте в него файлы __init__.py&lt;br /&gt;
и filters.py. В filters.py напишите:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; line=&amp;quot;GESHI_NORMAL_LINE_NUMBERS&amp;quot;&amp;gt;&lt;br /&gt;
from django import template&lt;br /&gt;
&lt;br /&gt;
register = template.Library()&lt;br /&gt;
&lt;br /&gt;
@register.filter&lt;br /&gt;
def exp(value, arg):&lt;br /&gt;
if value.isdigit() and arg.isdigit():&lt;br /&gt;
return int(value)**int(arg)&lt;br /&gt;
else:&lt;br /&gt;
return '&amp;lt;span style=“color:red”&amp;gt;Error&amp;lt;/span&amp;gt;'&lt;br /&gt;
exp.is_safe = True&amp;lt;/source &amp;gt;&lt;br /&gt;
Мы создали фильтр exp, который получает значение и показатель степени и возводит одно в другое; если аргументы не являются числами, генерируется ошибка. В строке 5 мы регистрируем&lt;br /&gt;
фильтр в системе с помощью декоратора. Строка 11 указывает,&lt;br /&gt;
что exp может возвращать HTML-код. Поскольку (в целях безопасности) он автоматически экранируется (&amp;lt; и &amp;gt; заменяются на &amp;amp;amp;lt; и&lt;br /&gt;
&amp;amp;amp;gt; и т.д.), то, желая видеть чистый HTML, мы должны запретить&lt;br /&gt;
такое поведение вручную. Следующим шагом является подгрузка&lt;br /&gt;
библиотеки фильтров в шаблон, для чего нужно добавить в него&lt;br /&gt;
следующую строку:&lt;br /&gt;
 {% load filters %}&lt;br /&gt;
Вообще-то Django ищет созданные библиотеки шаблонов в корне приложения, поэтому наш фильтр пока не будет доступен. Это&lt;br /&gt;
не очень удобно, особенно если мы хотим использовать один и тот&lt;br /&gt;
же фильтр во многих приложениях. Решение – создать для проекта&lt;br /&gt;
единую библиотеку, а в приложения помещать лишь символьные&lt;br /&gt;
ссылки на нее.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;ln -s /var/www/myproject/templatetags/ /var/www/myproject/news/&amp;lt;/source&amp;gt;&lt;br /&gt;
Теперь проверим работу фильтра, добавив в какой-нибудь шаблон&lt;br /&gt;
строку.&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{ &amp;quot;4&amp;quot;|exp:&amp;quot;4&amp;quot; }}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Во время компиляции она будет заменена на 256. Если же мы&lt;br /&gt;
напишем&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{ &amp;quot;a&amp;quot;|exp:&amp;quot;4&amp;quot; }}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
то увидим слово «Error», выделенное красным цветом.&lt;br /&gt;
Кстати, если бы мы не указали в строке 11 фильтра exp.is_safe= True, можно было бы просто применить фильтр safe прямо в&lt;br /&gt;
шаблоне:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{ &amp;quot;a&amp;quot;|exp:&amp;quot;4&amp;quot;|safe }}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
После регистрации фильтра в системе, информация о нем становится доступной по адресу http://127.0.0.1:8000/admin/doc/filters/&lt;br /&gt;
(рис. 4)&lt;br /&gt;
[[Изображение:LXF108 87 1.png|frame|center|Рис. 4. Система любезно подскажет, как использовать созданный вами фильтр.]]&lt;br /&gt;
&lt;br /&gt;
=== Компоненты ===&lt;br /&gt;
Если нам надо выполнить какие-либо действия до или после того,&lt;br /&gt;
как будет вызвано представление, либо в случае ошибки, можно создать свой компонент (middleware) или воспользоваться&lt;br /&gt;
поставляемым с Django. Мы уже делали это, когда изучали кэширование ([[LXF107:Django|LXF107]]). Напомню, что в файле settings.py есть кортеж&lt;br /&gt;
MIDDLEWARE_CLASSES, который перечисляет компоненты, задействованные в проекте. У нас это:&lt;br /&gt;
* django.middleware.common.CommonMiddleware Решает общие задачи: нормализует URL (добавляет префикс www и завершающий /), запрещает доступ к сайту определенным роботам, взаимодействует с Etag.&lt;br /&gt;
* django.contrib.sessions.middleware.SessionMiddleware Это сессии.&lt;br /&gt;
* django.contrib.auth.middleware.AuthenticationMiddleware А это – авторизация.&lt;br /&gt;
* django.middleware.doc.XViewMiddleware Используется для автоматического документирования Django.&lt;br /&gt;
* django.middleware.locale.LocaleMiddleware Интернационализация.&lt;br /&gt;
Помимо перечисленных выше, в Django доступны следующие&lt;br /&gt;
компоненты (django.middleware.*):&lt;br /&gt;
* gzip.GZipMiddleware Сжатие отправляемой страницы для экономии трафика.&lt;br /&gt;
* http.ConditionalGetMiddleware Поддержка условных GET-запросов для работы с Last-Modified и Etag.&lt;br /&gt;
* http.SetRemoteAddrFromForwardedFor Обратное проксирование.&lt;br /&gt;
* cache.CacheMiddleware Тот самый кэш, с которым мы сталкивались на прошлом уроке.&lt;br /&gt;
* transaction.TransactionMiddleware Компонент для включения в SQL-запросы транзакционных конструкций: COMMIT, ROLLBACK.&lt;br /&gt;
Заметьте, что не все базы данных поддерживают транзакции.&lt;br /&gt;
&lt;br /&gt;
И, наконец, django.contrib.csrf.middleware.CsrfMiddleware, защищающее от CSRF-атак.&lt;br /&gt;
&lt;br /&gt;
По сложившейся уже традиции, рассмотрим, как написать свой&lt;br /&gt;
собственный компонент. С точки зрения программиста, это просто&lt;br /&gt;
класс Python, имеющий ряд методов, вызываемых Django в определенные моменты времени. Первым из них является конструктор&lt;br /&gt;
__init__(self), регистрирующий компонент в системе. Дальше следуют методы, определяющие порядок выполнения кода:&lt;br /&gt;
* process_request() – запускается после того, как поступил запрос,но перед тем как Django начнет искать запрашиваемый адрес в URL-картах;&lt;br /&gt;
* process_view() – отрабатывает, когда конкретное представление уже определено, но еще не запущено;&lt;br /&gt;
* process_response() – выполняется после представления.&lt;br /&gt;
Используется для сжатия сгенерированного HTML.&lt;br /&gt;
process_exception() – вызывается, если что-то пошло не так или&lt;br /&gt;
было возбуждено необработанное исключение.&lt;br /&gt;
&lt;br /&gt;
Вот, в сущности, и все. Впрочем, нет – взгляните на врезку И&lt;br /&gt;
прочая, прочая, прочая, почитайте документацию или свободную&lt;br /&gt;
книгу о Django – Django Book (http://www.djangobook.com); если же вам&lt;br /&gt;
больше по душе русский, советую заглянуть на http://cargo.caml.ru/djangobook. Наконец, примените полученные знания на практике – и дайте нам знать, если у вас получится что-то действительно стоящее!&lt;br /&gt;
&lt;br /&gt;
{{Врезка|center|&lt;br /&gt;
|Заголовок=И прочая, прочая, прочая...&lt;br /&gt;
|Содержание=За четыре урока мы успели рассмотреть почти все возможности&lt;br /&gt;
Django, но кое-что осталось неохваченным...&lt;br /&gt;
*; Электронная почта&lt;br /&gt;
Django предлагает высокоуровневый API для отправки письма в&lt;br /&gt;
одно действие:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;from django.core.mail import send_mail&lt;br /&gt;
send_mail('Тема', 'сообщение.', 'from@example.com', ['to@example.com'], fail_silently=False)&amp;lt;/source&amp;gt;&lt;br /&gt;
Кроме того, есть функции массовой рассылки сообщений, оповещения администраторов и менеджеров сайта, а также работы с&lt;br /&gt;
различным содержимым (HTML, текст, графика и т.п.)&lt;br /&gt;
*; CSV и PDF&lt;br /&gt;
Django позволяет легко формировать файлы с данными, разделенными запятыми (CSV), а также PDF-документы, используя&lt;br /&gt;
библиотеку ReportLab (http://www.reportlab.org/rl_toolkit.html).&lt;br /&gt;
*; Постраничный вывод&lt;br /&gt;
Когда количество объектов настолько велико, что одной страницы становится мало, на помощь приходит специальный класс&lt;br /&gt;
Paginator, который помогает организовать постраничный вывод:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt; from django.core.paginator import Paginator&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; objects = ['django', 'python', 'mysql', 'apache']&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; p = Paginator(objects, 2)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; page1 = p.page(1)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; page1.object_list&lt;br /&gt;
['django', 'python']&amp;lt;/source&amp;gt;&lt;br /&gt;
Поскольку большинство наших объектов хранятся в базе данных,&lt;br /&gt;
Django также предлагает класс QuerySetPaginator, который принимает не список, а множество объектов из СУБД.&lt;br /&gt;
*; Карты сайта&lt;br /&gt;
Хотите, чтобы ваш сайт правильно индексировался поисковыми&lt;br /&gt;
машинами? Необходимо создать его карту! Django поможет и&lt;br /&gt;
здесь, а функция django.contrib.sitemaps.ping_google «заставит»&lt;br /&gt;
Google обновить индексы для вашего сайта.&lt;br /&gt;
*; Управление несколькими сайтами&lt;br /&gt;
Одной из задач, с которой успешно справляется Django, является&lt;br /&gt;
управление несколькими схожими по тематике сайтами из одной&lt;br /&gt;
инсталляции. Проект первоначально разрабатывался как платформа для новостных порталов, и одна новость могла появиться&lt;br /&gt;
сразу на нескольких ресурсах.&lt;br /&gt;
*; В помощь дизайнерам&lt;br /&gt;
Подгрузив к шаблонам модуль помощи дизайнерам:&lt;br /&gt;
 {% load webdesign %}&lt;br /&gt;
вы получите в свое распоряжение тэг {% lorem %}, с помощью&lt;br /&gt;
которого можно выводить известную латинскую фразу «lorem&lt;br /&gt;
ipsum ...» для заполнения шаблонов «рыбой».&lt;br /&gt;
*; И более того&lt;br /&gt;
Django содержит много других «вкусностей», которые очень&lt;br /&gt;
хорошо описаны в прилагающейся документации на английском&lt;br /&gt;
языке.&lt;br /&gt;
|Ширина=}}&lt;/div&gt;</summary>
		<author><name>Steve</name></author>	</entry>

	</feed>