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

LXF108:Django

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
м
м (Акроним переименовал страницу LХF100-101:Aнaнac в LXF108:Django поверх перенаправления)
 
(не показаны 10 промежуточных версий 3 участников)
Строка 1: Строка 1:
Cycle {{/ Django}}
+
{{Цикл/Django}}
== == The final touches
+
== Финальные штрихи ==
:''PART 4 ​​Lessons Django comes to an end, there comes a time for exams - if not for you, for applications for sure. '''Nikita Shultays''' (http://shultais.ru) will deal with testing and go over other features of this framework.''
+
: ''ЧАСТЬ 4 Уроки Django подходят к концу, наступает пора экзаменов – если не для вас, то для приложений уж точно. '''Никита Шультайс''' (http://shultais.ru) разберется с тестированием и пробежится по другим возможностям этого каркаса.''
  
Newsline is ready - but whether it will meet expectations
+
Новостная лента готова – но оправдает ли она ожидания
users? The answer to this question can be tested, the best - in the real world, but some
+
пользователей? Ответ на этот вопрос может дать тестирование, лучше всего – в реальных условиях; но какие-то
basic things you can check at the stage of development [http://www.thesiswritingservice.com/ thesis writers]. If you
+
основные вещи можно проверить еще на этапе разработки. Если вы
time to look at the tutorial [[LXF108: Rails | Rails]], you already know about the methodology of TDD. However, we'll go the other way, and will test [http://www.diamondlinks.net link building service]
+
успели заглянуть в учебник [[LXF108:Rails|Rails]], то уже знаете о методологии TDD. Мы, однако, пойдем другим путем, и будем тестировать
application not to write, and after.
+
приложение не до написания, а после.
  
The point is - a serious and complex, as we need to consider
+
Дело это – серьезное и сложное, так как нам нужно учитывать
interaction with the database, a compilation of templates,[http://www.mycaal.com loan modification] processes and GET-
+
взаимодействие с БД, компиляцию шаблонов, обработку GET- и
POST-requests and other system components: a failure in any of
+
POST-запросов и прочие компоненты системы: сбой в любом из
They can cause disrupt the entire site. Go to this problem
+
них может вызвать нарушить работу всего сайта. К данной задаче
can be approached from two sides:
+
можно подойти с двух сторон:
* Testing in your browser. We are talking about programs Twill (http://twill.idyll.org) and Selenium (http://selenium.openqa.org): they "remember" the sequence of your actions for each page, and then reproduce it on demand. For example, you can type in form fields obviously incorrect data, get the expected error and repeat the test whenever a major change in the code of your application.
+
* Тестирование в браузере. Речь идет о программах Twill (http://twill.idyll.org) и Selenium (http://selenium.openqa.org): они «запоминают» последовательность ваших действий для каждой страницы, а затем воспроизводят ее по запросу. Например, можно ввести в поля формы заведомо неверные данные, получить ожидаемую ошибку и повторять этот тест при каждом серьезном изменении в коде вашего приложения.
* Testing on the server. And then Django does not leave us to fend for themselves, offering just two options: doctest (tested via documentation) and unittest (unit testing), plus a special client to send a GET-and POST-requests.
+
* Тестирование на сервере. И тут Django не оставляет нас на произвол судьбы, предлагая сразу два варианта: doctest (тестирование через документацию) и unittest (модульное тестирование), плюс специальный клиент для отправки GET- и POST-запросов.
  
If you've been programming in Python, then you probably
+
Если вы давно программируете на Python, то вам, наверное,
will be closer doctest, and migrants from the Java world have more in
+
будет ближе doctest, а мигрантам из мира Java скорее придется по
taste unittest. There are no restrictions on their use is imposed: you can choose one system or use both at once. We also discuss the doctest.
+
вкусу unittest. Никаких ограничений на их использование не накладывается: вы можете выбрать одну систему или применять обе сразу. Мы же остановимся на doctest.
  
=== Document it! ===
+
=== Документируй это! ===
Line documentation in Python - it is plain text that you place
+
Строка документации в Python – это обычный текст, размещаемый
after the definition of a function or class directly in the source
+
после определения функции или класса непосредственно в исходном
code. It also provides content for the attribute __doc__. As
+
коде. Она же предоставляет содержимое для атрибута __doc__. Как
Typically, it is placed in triple quotes ("""), that allows you to enter
+
правило, ее помещают в тройные кавычки ("""), что позволяет вводить
complex structures with line breaks, indentation, the same quotes and ... tests. That's what we use.
+
сложные конструкции с переносами строк, отступами, теми же кавычками и... тестами. Этим мы и воспользуемся.
  
Tests can be found in the model files (models.py) - to check the latest - and in special files tests.py, located
+
Тесты могут находится в файлах моделей (models.py) – для проверки последних – и в специальных файлах tests.py, расположенных
in the application directory. For example, create a news / tests.py
+
в директории приложения. К примеру, создайте файл news/tests.py
to the following:
+
такого содержания:
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
# -*- Coding: utf-8 -*-
+
# -*- coding: utf-8 -*-
  
"" "
+
"""
>>> From news.models import News
+
>>> from news.models import News
>>> From datetime import datetime
+
>>> from datetime import datetime
>>> News = News (title = "Title", description = "Description", pub_date = datetime.now (), text = "text")
+
>>> news = News(title="Заголовок",description="Описание",pub_date=datetime.now(), text="Текст")
>>> News.save ()
+
>>> news.save()
>>> News = News.objects.get (pk = 1)
+
>>> news = News.objects.get(pk=1)
>>> Print news.title.encode ('utf-8')
+
>>> print news.title.encode('utf-8')
 Title
+
Заголовок
"" "
+
"""
</ Source>
+
</source>
In line 1 encoding, but since the third is very
+
В строке 1 задается кодировка, а начиная с третьей идет сам
test. Note that each line begins with three characters "more" (>>>), in the interactive mode, Python. Line 10
+
тест. Заметьте, что каждая строка начинается с трех знаков «больше» (>>>), как в интерактивном режиме работы Python. В строке 10
These characters do not, because it contains the expected output
+
этих знаков нет, так как она содержит ожидаемый вывод команды
print from line 9.
+
print со строки 9.
  
[[Image: LXF108 85 1.png | thumb | 200px | Fig. 1. Test passed successfully!]]
+
[[Изображение:LXF108 85 1.png|thumb|200px|Рис. 1. Тест пройден удачно!]]
Before running the test, you need to add in settings.py
+
Перед тем, как запустить тест, в settings.py нужно добавить
line
+
строку
 TEST_DATABASE_CHARSET = "UTF8"
+
TEST_DATABASE_CHARSET="UTF8"
to file encoding and the database match. Before performing the test, Django will create a special auxiliary databases, so
+
чтобы кодировки файла и базы данных совпадали. Перед выполнением теста Django создаст специальную вспомогательную БД, поэтому
the user specified in settings.DATABASE_USER, must have
+
пользователь, указанный в settings.DATABASE_USER, должен иметь
the appropriate authority. To begin testing, type:
+
соответствующие права. Для начала тестирования введите команду:
 python manage.py test news
+
python manage.py test news
after which you will see something that shows
+
после выполнения которой вы увидите примерно то, что показано
Fig. 1.
+
на рис. 1.
  
Messages similar to appear during the creation of tables
+
Сообщения похожи на появляющиеся во время создания таблиц
when you first install, but now it happens in a test database. In
+
при первой установке, но теперь все происходит в тестовой БД. В
end shows the number of tests performed, their results and
+
конце отображается число выполненных тестов, их результаты и
notified about the destruction of a test material. We checked our
+
уведомление об уничтожении тестовой базы. Мы проверяли наше
application (news), but, as you know, Django provides a few
+
приложение (news), но, как вы помните, Django содержит несколько
own applications and representations (eg, "admin") -
+
собственных приложений и представлений (например, «админку»)
and they also supplied with their tests. To perform them all,
+
и они тоже снабжаются своими тестами. Чтобы выполнить их все,
must enter the command:
+
нужно ввести команду:
 python manage.py test
+
python manage.py test
adding previously in the main file the following URL-card
+
добавив предварительно в главный файл URL-карт следующие
lines:
+
строки:
<source lang="python"> urlpatterns + = patterns ('django.contrib.auth.views',
+
<source lang="python">urlpatterns += patterns('django.contrib.auth.views',
url (r '^ auth / password_reset /$',' password_reset'),
+
url(r'^auth/password_reset/$','password_reset'),
) </ Source>
+
)</source>
Here we include one of the built-in views, designed to recover your password. This is necessary since
+
Здесь мы подключаем одно из встроенных представлений, предназначенное для восстановления пароля. Это необходимо, так как при
testing of the entire project is being accessed at the specified URL,
+
тестировании всего проекта происходит обращение по указанному URL,
and if the view is not specified, the test will fail. By the way, you
+
и если представление не определено, тест будет провален. Кстати, вы
also can try password_reset in (Fig. 2).
+
тоже можете попробовать password_reset в работе (рис. 2).
[[Image: LXF108 85 2.png | frame | center | Fig. 2. Forgot your password? This problem Django!]]
+
[[Изображение:LXF108 85 2.png|frame|center|Рис. 2. Забыли пароль? Это проблемы Django!]]
  
=== === Network Simulator
+
=== Имитатор Сети ===
The number of tests has already reached six, but in addition to creating and
+
Количество тестов уже достигло шести, но помимо создания и
retrieve objects from the database, we need to test the response to
+
извлечения объектов из базы, нам нужно проверить реакцию на
GET-and POST-requests. As you know, for these purposes there
+
GET- и POST-запросы. Как вы знаете, для этих целей существует
special client: it emulates the query and returns the variables that are passed to the template for this URL. Add the
+
специальный клиент: он эмулирует запрос и возвращает переменные, которые передаются в шаблон для данного URL. Добавьте в
tests.py file after line 10 the following code:
+
файл tests.py после строки 10 следующий код:
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" line start="11">
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS" line start="11">
>>> From django.contrib.auth.models import User
+
>>> from django.contrib.auth.models import User
>>> User = User.objects.create_user ('django_guru', 'user@example.com', 'password')
+
>>> user = User.objects.create_user('django_guru', 'user@example.com', 'password')
>>> User.save ()
+
>>> user.save()
>>> From django.test.client import Client
+
>>> from django.test.client import Client
>>> C = Client ()
+
>>> c = Client()
>>> C.login (username = 'django_guru', password = "password")
+
>>> c.login(username='django_guru',password=“password”)
 
True
 
True
>>> Response = c.get ('/ news / 1 /')
+
>>> response = c.get('/news/1/')
>>> Response.status_code
+
>>> response.status_code
 
200
 
200
>>> Print response.context [0] ['user']. Username
+
>>> print response.context[0]['user'].username
 
django_guru
 
django_guru
>>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text':»»})
+
>>> response = c.post('/news/1/',{'username':“testuser”,'text':»»})
>>> Response.status_code
+
>>> response.status_code
 
200
 
200
>>> Response = c.post ('/ news / 1 /',{' username': "testuser", 'text': »Comment text»})
+
>>> response = c.post('/news/1/',{'username':“testuser”,'text':»Comment text»})
>>> Response.status_code
+
>>> response.status_code
 
302
 
302
>>> From news.models import Comment
+
>>> from news.models import Comment
>>> Comment = Comment.objects.get (news = news)
+
>>> comment = Comment.objects.get(news=news)
>>> Print comment.text
+
>>> print comment.text
Comment text </ source>
+
Comment text</source>
See what is happening here. In lines 11-13 we create
+
Разберемся, что здесь происходит. В строках 11–13 мы создаем
New User (django_guru), and in 14-15 - the test client. In
+
нового пользователя (django_guru), а в 14–15 – тестовый клиент. В
line 16 django_guru authenticated, and now all of the system
+
строке 16 django_guru авторизуется, и отныне все действия в системе
will be performed by  in his name. On line 18 we went to our first news page, passing the client means GET-request.
+
будут совершаться от его имени. В строке 18 мы переходим на страницу нашей первой новости, передав средствами клиента GET-запрос.
To check that we have succeeded, we study the server response code
+
Для проверки, что нам это удалось, мы изучаем код ответа сервера
(Line 19) - it should be 200, or test will fail.
+
(строка 19) – он должен равняться 200, или тест будет провален.
Then (lines 21-22), the reading of additional response data, we
+
Затем (строки 21–22), чтением дополнительных данных ответа, мы
verify that the request is made a registered user
+
убеждаемся, что запрос сделал зарегистрированный пользователь
django_guru. Now it's time to leave a comment - not in vain
+
django_guru. Теперь самое время оставить комментарий – не зря же
We logged in? Line 23 is generated POST-request (second
+
мы авторизовались? В строке 23 генерируется POST-запрос (второй
argument to post () - dictionary data sent to the server).
+
аргумент метода post() – словарь отсылаемых на сервер данных).
Note that the value of the key text is blank, and
+
Обратите внимание, что значение ключа text оставлено пустым, а
hence, the comment is not added, but the server still must return code 200 (line 25). But in line 26 we pass
+
значит, комментарий не добавится, однако сервер по-прежнему должен возвращать код 200 (строка 25). А вот в строке 26 мы передаем
all necessary data, and because after the comment we
+
все необходимые данные, и так как после создания комментария нас
redirected to the news page, the response code should be equal
+
перенаправляют на страницу новости, код ответа должен быть равен
302 (The requested URL moved). Lines 29-32 verify that
+
302 (Требуемый URL перемещен). В строках 29–32 проверяется, что
comment was actually added, we compare the text
+
комментарий был действительно добавлен: мы сравниваем его текст
with an initial value. Whew ... test passed.
+
с исходным значением. Уфф... тест пройден.
  
Real Simple Syndication === ===
+
=== Действительно простая синдикация ===
What is a news site without the tape? RSS and / or Atom feeds are everywhere - will be
+
Какой новостной сайт без ленты? RSS и/или Atom есть везде – будут
and here, and Django us help you. Open the main file URL-cards and add to the end of the following lines:
+
и у нас, а Django нам в этом поможет. Откройте главный файл URL-карт и добавьте в его конец следующие строки:
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 
from feeds import LatestNews
 
from feeds import LatestNews
  
 
feeds = {
 
feeds = {
'Latest': LatestNews,
+
'latest': LatestNews,
 
}
 
}
urlpatterns + = patterns ('',
+
urlpatterns += patterns('',
(R '^ feeds / (? P <url> .*)/$',' django.contrib.syndication.views.feed ',
+
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'Feed_dict': feeds}),
+
{'feed_dict': feeds}),
 
)
 
)
</ Source>
+
</source>
Next you need to prepare a tape LatestNews, which we import at row 1. Create the root directory of the project feeds the file
+
Далее нужно приготовить ленту LatestNews, которую мы импортируем в строке 1. Создайте в корне проекта каталог feeds с файлом
__init__.py as follows:
+
__init__.py следующего содержания:
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
# -*- Coding: utf-8 -*-
+
# -*- coding: utf-8 -*-
  
 
from django.contrib.syndication.feeds import Feed
 
from django.contrib.syndication.feeds import Feed
Строка 151: Строка 151:
 
from django.contrib.syndication.feeds import FeedDoesNotExist
 
from django.contrib.syndication.feeds import FeedDoesNotExist
  
class LatestNews (Feed):
+
class LatestNews(Feed):
title = "Latest news from our site"
+
title = "Последние новости нашего сайта"
description = "Recent developments on the site mysite.com"
+
description = "Последние события на сайте mysite.com"
 
link = "http://127.0.0.1:8000/news/"
 
link = "http://127.0.0.1:8000/news/"
  
def items (self):
+
def items(self):
return News.objects.order_by ("-pub_date") [: 5]
+
return News.objects.order_by("-pub_date")[:5]
  
def item_link (self, obj):
+
def item_link(self, obj):
 
from django.core.urlresolvers import reverse
 
from django.core.urlresolvers import reverse
return 'http://127.0.0.1:8000% s'% reverse ('news.news_detail', kwargs = {"news_id": obj.pk})
+
return 'http://127.0.0.1:8000%s' % reverse('news.news_detail',kwargs={"news_id":obj.pk})
</ Source>
+
</source>
[[Image: LXF108 86 1.png | thumb | 250px | Fig. 3. Firefox offers to subscribe to our news website updated - now hold on!]]
+
[[Изображение:LXF108 86 1.png|thumb|250px|Рис. 3. Firefox предлагает подписаться на обновления нашего новостного сайта – теперь держитесь!]]
Fields title, description and link class LatestNews are required and are responsible for elements of the same name RSS. The method items ()
+
Поля title, description и link класса LatestNews являются обязательными и отвечают за одноименные элементы RSS. Метод items()
passes the required objects in the tape, and item_link () is responsible for the link
+
передает в ленту требуемые объекты, а item_link() отвечает за ссылку
to the site. Now create a directory of feeds media / templates, and add
+
на сайт. Теперь создайте каталог feeds в media/templates и добавьте
in it two files, latest_description.html and latest_title.html: they will
+
в него два файла, latest_description.html и latest_title.html: они будут
responsible for the news column form. In lates_description.html write:
+
отвечать за вид новостной ленты. В lates_description.html напишите:
 <nowiki> {{obj.description}} </ nowiki>
+
<nowiki>{{ obj.description }}</nowiki>
and latest_title.html:
+
а в latest_title.html:
 <nowiki> [{{obj.pub_date | date: "dmY"}}] {{obj.title}} </ nowiki>
+
<nowiki>[{{ obj.pub_date|date:"d.m.Y" }}] {{ obj.title }}</nowiki>
Obj is a record of the sample, we
+
Объект obj представляет собой запись из выборки, которую мы
return in line 13, file feeds / __init__.py. Having at
+
возвращаем в строке 13 файла feeds/__init__.py. Пройдя по адресу
http://127.0.0.1:8000/feeds/latest/, we shall offer Firefox
+
http://127.0.0.1:8000/feeds/latest/, мы увидим предложение Firefox
save feed. Members KDE, is likely to prefer
+
сохранить ленту новостей. Пользователи KDE, вероятно, предпочтут
Akregator - with him, too, there is no problem (Fig. 3, 4)
+
Akregator – с ним тоже нет никаких проблем (рис. 3, 4)
  
=== === Understanding
+
=== Общие представления ===
To make life easier for web-developer, Django has included a large
+
Чтобы облегчить жизнь web-разработчика, Django включил большое
number of representations to solve standard problems. For example, adding
+
число представлений для решения стандартных задач. Так, добавив
in the main file URL-mapping the following code:
+
в главный файл URL-карт следующий код:
 
<source lang="python">
 
<source lang="python">
 
from django.views.generic.list_detail import object_list
 
from django.views.generic.list_detail import object_list
 
from news.models import News
 
from news.models import News
urlpatterns + = patterns ('',
+
urlpatterns += patterns('',
('^ Lastnews / $', object_list, {
+
('^lastnews/$', object_list, {
'Queryset': News.objects.all (). Order_by ('-pub_date') [: 10]
+
'queryset': News.objects.all().order_by('-pub_date')[:10],
'Template_name': 'news / last_news.html',
+
'template_name':'news/last_news.html',
'Template_object_name': 'last_news'})
+
'template_object_name':'last_news'})
) </ Source>
+
)</source>
as well as replacing the file in news / templates / news / last_news.html
+
а также заменив в файле news/templates/news/last_news.html
 {% For news in last_news%}
+
{% for news in last_news %}
on
+
на
 {% For news in last_news_list%}
+
{% for news in last_news_list %}
we will be able to view the latest news at
+
мы сможем просматривать последние новости по адресу
http://127.0.0.1:8000/lastnews/, causing no idea news.last_news. To make available both options must be found in presenting the line news.last_news
+
http://127.0.0.1:8000/lastnews/, не вызывая представление news.last_news. Чтобы сделать доступными оба варианта, нужно найти в представлении news.last_news строку
 "Last_news": news,
+
"last_news":news,
and replace it with
+
и заменить ее на
 "Last_news_list": news,
+
"last_news_list":news,
As you may have guessed, the general idea object_list designed to work with a list of objects. Still there is a submission for
+
Как вы уже догадались, общее представление object_list предназначено для работы со списком объектов. Еще есть представления для
O objects, depending on the date (django.views.generic.date_based .*), which makes it very easy to create backups of records:
+
вывода объектов в зависимости от даты (django.views.generic.date_based.*), что позволяет очень просто создавать архивы записей:
* Archive_index - withdrawal of the last object added to the database;
+
* archive_index – вывод последних объектов, добавленных в базу данных;
* Archive_ {year, month, week, day, today} - the output of all the objects in a given year, month, week, day or today;
+
* archive_{year,month,week,day,today} – вывод всех объектов за определенный год, месяц, неделю, день или за сегодня;
* Object_detail - the output of one object for a particular day.
+
* object_detail – вывод одного объекта за определенный день.
General ideas are available for creating, updating and
+
Доступны общие представления для создания, обновления и
deleting objects. They all work a little faster than by hand, but can solve only the most basic tasks. If the data in your application are selected from several
+
удаления объектов. Все они работают немного быстрее, чем созданные вручную, но позволяют решать лишь самые элементарные задачи. Если данные в вашем приложении выбираются из нескольких
tables and is accompanied by the calculations, the overall presentation
+
таблиц и это сопровождается расчетами, то общие представления
will not help - then, they are common.
+
не помогут – на то они и общие.
  
=== Add === variables on the fly
+
=== Добавляем переменные на лету ===
In the depths of the global context Django hide processors, the main task - to supply the template variables
+
В глубинах Django скрываются глобальные контекстные процессоры, основная задача которых – снабжать шаблоны переменными
and objects. Learn which ones are connected, you can in a tuple
+
и объектами. Узнать, какие из них подключены, можно в кортеже
TEMPLATE_CONTEXT_PROCESSORS in your settings.py. For example,
+
TEMPLATE_CONTEXT_PROCESSORS в файле settings.py. Например, у
We are now working the following processors:
+
нас сейчас работают следующие процессоры:
* Auth - information about the user: the object user, his rights of access and the messages that were sent to him;
+
* auth – информация о пользователе: объект user, его права доступа и сообщения, которые были ему отправлены;
* I18n - information about the current language of the site and the client;
+
* i18n – сведения о текущем языке сайта и клиента;
* Request - information on request.
+
* request – данные о запросе.
Besides them, there is a processor debug, sending in
+
Кроме них, существует еще процессор debug, передающий в
pattern data of the executed SQL-queries, plus we can
+
шаблон данные о выполненных SQL-запросах, плюс мы можем
write your own! To do this we create in the root of our
+
написать свой собственный! Для этого создадим в корне нашего
project directory and add the processors in it two files: __init__.py
+
проекта каталог processors и добавим в него два файла: __init__.py
and context_processors.py. The latter should contain the following code:
+
и context_processors.py. Последний должен содержать такой код:
 
<source lang="python">
 
<source lang="python">
 
import settings
 
import settings
def site_settings (request):
+
def site_settings(request):
return {'SETTINGS': settings} </ source>
+
return {'SETTINGS': settings}</source>
To connect the processor, just list it in the tuple
+
Чтобы подключить процессор, просто перечислите его в кортеже
TEMPLATE_CONTEXT_PROCESSORS. We check availability:
+
TEMPLATE_CONTEXT_PROCESSORS. Проверим работоспособность:
add a template news.html following:
+
добавим в шаблон news.html следующее:
 <nowiki> {{SETTINGS.TIME_ZONE}} </ nowiki>
+
<nowiki>{{ SETTINGS.TIME_ZONE }}</nowiki>
Of course, TIME_ZONE can be replaced by any other variable that is defined in settings.py.
+
Конечно, TIME_ZONE можно заменить на любую другую переменную, определенную в settings.py.
  
=== === Sam himself filter
+
=== Сам себе фильтр ===
With filters we met in [[LXF105: Django | LXF105]], but often there are situations when supplied with Django options are not enough. To write your own filter, create a radically
+
С фильтрами мы познакомились еще в [[LXF105:Django|LXF105]], однако часто возникают ситуации, когда поставляемых с Django вариантов недостаточно. Чтобы написать свой собственный фильтр, создайте в корне
project directory templatetags / and add the files __init__.py
+
проекта каталог templatetags/ и добавьте в него файлы __init__.py
and filters.py. In filters.py write:
+
и filters.py. В filters.py напишите:
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS">
 
from django import template
 
from django import template
  
register = template.Library ()
+
register = template.Library()
  
@ Register.filter
+
@register.filter
def exp (value, arg):
+
def exp(value, arg):
if value.isdigit () and arg.isdigit ():
+
if value.isdigit() and arg.isdigit():
return int (value) ** int (arg)
+
return int(value)**int(arg)
 
else:
 
else:
return '<span style="color:red"> Error </ span>'
+
return '<span style=“color:red”>Error</span>'
exp.is_safe = True </ source>
+
exp.is_safe = True</source >
We have created a filter exp, which will have a value and an exponent and raises one another, if the arguments are not numbers, an error is generated. In line 5 we register
+
Мы создали фильтр exp, который получает значение и показатель степени и возводит одно в другое; если аргументы не являются числами, генерируется ошибка. В строке 5 мы регистрируем
filter in the system with the help of a decorator. Line 11 indicates
+
фильтр в системе с помощью декоратора. Строка 11 указывает,
that exp can return HTML-code. Because (for security), it automatically screened (<and> are replaced by &lt; and
+
что exp может возвращать HTML-код. Поскольку (в целях безопасности) он автоматически экранируется (< и > заменяются на &amp;lt; и
&gt; etc.), then, wanting to see pure HTML, we should prohibit
+
&amp;gt; и т.д.), то, желая видеть чистый HTML, мы должны запретить
this behavior manually. The next step is loading of
+
такое поведение вручную. Следующим шагом является подгрузка
library of filters to the template, which you need to add the
+
библиотеки фильтров в шаблон, для чего нужно добавить в него
the following line:
+
следующую строку:
 {% Load filters%}
+
{% load filters %}
In fact, Django looks for templates created by the library in the application root, so our filter still will not be available. It
+
Вообще-то Django ищет созданные библиотеки шаблонов в корне приложения, поэтому наш фильтр пока не будет доступен. Это
not very convenient, especially if we want to use the
+
не очень удобно, особенно если мы хотим использовать один и тот
the same filter in many applications. The solution - to create a project
+
же фильтр во многих приложениях. Решение – создать для проекта
single library, and put in applications merely symbolic
+
единую библиотеку, а в приложения помещать лишь символьные
references to it.
+
ссылки на нее.
<source lang="bash"> ln-s / var / www / myproject / templatetags / / var / www / myproject / news / </ source>
+
<source lang="bash">ln -s /var/www/myproject/templatetags/ /var/www/myproject/news/</source>
Now test the filter by adding any template
+
Теперь проверим работу фильтра, добавив в какой-нибудь шаблон
line.
+
строку.
 <nowiki> {{"4" | exp: "4"}} </ nowiki>
+
<nowiki>{{ "4"|exp:"4" }}</nowiki>
At compile time, it will be replaced by 256. If we
+
Во время компиляции она будет заменена на 256. Если же мы
write
+
напишем
 <nowiki> {{"a" | exp: "4"}} </ nowiki>
+
<nowiki>{{ "a"|exp:"4" }}</nowiki>
we see the word «Error», in red.
+
то увидим слово «Error», выделенное красным цветом.
By the way, if we did not specify a filter in line 11 exp.is_safe = True, you could simply apply the filter directly into the safe
+
Кстати, если бы мы не указали в строке 11 фильтра exp.is_safe= True, можно было бы просто применить фильтр safe прямо в
template:
+
шаблоне:
 <nowiki> {{"a" | exp: "4" | safe}} </ nowiki>
+
<nowiki>{{ "a"|exp:"4"|safe }}</nowiki>
After registering a filter in the system, information about it becomes available at http://127.0.0.1:8000/admin/doc/filters/
+
После регистрации фильтра в системе, информация о нем становится доступной по адресу http://127.0.0.1:8000/admin/doc/filters/
(Fig. 4)
+
(рис. 4)
[[Image: LXF108 87 1.png | frame | center | Fig. 4. The system politely tells you how to use the filter you created.]]
+
[[Изображение:LXF108 87 1.png|frame|center|Рис. 4. Система любезно подскажет, как использовать созданный вами фильтр.]]
  
=== === The components of
+
=== Компоненты ===
If we have to perform any action before or after
+
Если нам надо выполнить какие-либо действия до или после того,
as would be caused by representation, or if an error occurs, you can create your own components (middleware), or use
+
как будет вызвано представление, либо в случае ошибки, можно создать свой компонент (middleware) или воспользоваться
supplied with Django. We've already done this, when studied caching ([[LXF107: Django | LXF107]]). I recall that in the settings.py file is a tuple
+
поставляемым с Django. Мы уже делали это, когда изучали кэширование ([[LXF107:Django|LXF107]]). Напомню, что в файле settings.py есть кортеж
MIDDLEWARE_CLASSES, which lists the components involved in the project. We are:
+
MIDDLEWARE_CLASSES, который перечисляет компоненты, задействованные в проекте. У нас это:
* Django.middleware.common.CommonMiddleware solve common problems: normalizes the URL (adds a www and the trailing /), prohibits access to the site specific robot interacts with Etag.
+
* django.middleware.common.CommonMiddleware Решает общие задачи: нормализует URL (добавляет префикс www и завершающий /), запрещает доступ к сайту определенным роботам, взаимодействует с Etag.
* Django.contrib.sessions.middleware.SessionMiddleware this session.
+
* django.contrib.sessions.middleware.SessionMiddleware Это сессии.
* Django.contrib.auth.middleware.AuthenticationMiddleware And this - authorization.
+
* django.contrib.auth.middleware.AuthenticationMiddleware А это – авторизация.
* Django.middleware.doc.XViewMiddleware used for automatic documentation Django.
+
* django.middleware.doc.XViewMiddleware Используется для автоматического документирования Django.
* Django.middleware.locale.LocaleMiddleware Internationalization.
+
* django.middleware.locale.LocaleMiddleware Интернационализация.
In addition to the above, the following are available in Django
+
Помимо перечисленных выше, в Django доступны следующие
components (django.middleware .*):
+
компоненты (django.middleware.*):
* Gzip.GZipMiddleware compression sends the page to save bandwidth.
+
* gzip.GZipMiddleware Сжатие отправляемой страницы для экономии трафика.
* Http.ConditionalGetMiddleware Support for conditional GET-requests to work with the Last-Modified and Etag.
+
* http.ConditionalGetMiddleware Поддержка условных GET-запросов для работы с Last-Modified и Etag.
* Http.SetRemoteAddrFromForwardedFor reverse proxying.
+
* http.SetRemoteAddrFromForwardedFor Обратное проксирование.
* Cache.CacheMiddleware The same cache, which we encountered in the previous lesson.
+
* cache.CacheMiddleware Тот самый кэш, с которым мы сталкивались на прошлом уроке.
* Transaction.TransactionMiddleware component for inclusion in SQL-queries of transaction structures: COMMIT, ROLLBACK.
+
* transaction.TransactionMiddleware Компонент для включения в SQL-запросы транзакционных конструкций: COMMIT, ROLLBACK.
Note that not all databases support transactions.
+
Заметьте, что не все базы данных поддерживают транзакции.
  
And finally, django.contrib.csrf.middleware.CsrfMiddleware, protecting against CSRF-attacks.
+
И, наконец, django.contrib.csrf.middleware.CsrfMiddleware, защищающее от CSRF-атак.
  
It has become a tradition, consider how to write your
+
По сложившейся уже традиции, рассмотрим, как написать свой
own components. From a programmer's standpoint, it's just
+
собственный компонент. С точки зрения программиста, это просто
Class Python, having a number of methods called Django at some point in time. The first is the constructor
+
класс Python, имеющий ряд методов, вызываемых Django в определенные моменты времени. Первым из них является конструктор
__init__ (self), registering the components in the system. Next are the methods of determining the order of the code:
+
__init__(self), регистрирующий компонент в системе. Дальше следуют методы, определяющие порядок выполнения кода:
* Process_request () - runs after the request, but before Django will look for the requested address in the URL-maps;
+
* process_request() – запускается после того, как поступил запрос,но перед тем как Django начнет искать запрашиваемый адрес в URL-картах;
* Process_view () - work out when the concrete representation is defined, but not yet started;
+
* process_view() – отрабатывает, когда конкретное представление уже определено, но еще не запущено;
* Process_response () - runs after the presentation.
+
* process_response() – выполняется после представления.
Used to compress the generated HTML.
+
Используется для сжатия сгенерированного HTML.
process_exception () - called when something goes wrong or
+
process_exception() – вызывается, если что-то пошло не так или
were instituted an unhandled exception.
+
было возбуждено необработанное исключение.
  
That is, in essence, that's all. But no - look at the sidebar and
+
Вот, в сущности, и все. Впрочем, нет – взгляните на врезку И
away, away, away, read the documentation or the free
+
прочая, прочая, прочая, почитайте документацию или свободную
a book about Django - Django Book (http://www.djangobook.com); if you
+
книгу о Django Django Book (http://www.djangobook.com); если же вам
prefer Russian, I advise you to look at http://cargo.caml.ru/djangobook. Finally, apply the acquired knowledge into practice - and let us know if you have something really worthwhile!
+
больше по душе русский, советую заглянуть на http://cargo.caml.ru/djangobook. Наконец, примените полученные знания на практике – и дайте нам знать, если у вас получится что-то действительно стоящее!
  
{{Box | center |
+
{{Врезка|center|
| Title =, etc., etc., other ...
+
|Заголовок=И прочая, прочая, прочая...
| Table of Contents = Over four lessons, we had to consider almost all possible
+
|Содержание=За четыре урока мы успели рассмотреть почти все возможности
Django, but something is left out ...
+
Django, но кое-что осталось неохваченным...
*, E-mail
+
*; Электронная почта
Django offers a high-level API to send a message to
+
Django предлагает высокоуровневый API для отправки письма в
one action:
+
одно действие:
<source lang="python"> from django.core.mail import send_mail
+
<source lang="python">from django.core.mail import send_mail
send_mail ('Subject', 'message.', 'from@example.com', ['to@example.com'], fail_silently = False) </ source>
+
send_mail('Тема', 'сообщение.', 'from@example.com', ['to@example.com'], fail_silently=False)</source>
In addition, there is a function of mass communications, alerts, site administrators and managers, as well as working with
+
Кроме того, есть функции массовой рассылки сообщений, оповещения администраторов и менеджеров сайта, а также работы с
different content (HTML, text, graphics, etc.)
+
различным содержимым (HTML, текст, графика и т.п.)
*; CSV and PDF
+
*; CSV и PDF
Django makes it easy to create data files, Comma Separated Values ​​(CSV), as well as PDF-documents using
+
Django позволяет легко формировать файлы с данными, разделенными запятыми (CSV), а также PDF-документы, используя
Library ReportLab (http://www.reportlab.org/rl_toolkit.html).
+
библиотеку ReportLab (http://www.reportlab.org/rl_toolkit.html).
*, Paged
+
*; Постраничный вывод
When the number of objects is so large that one page is enough, have the support of a special class
+
Когда количество объектов настолько велико, что одной страницы становится мало, на помощь приходит специальный класс
Paginator, who helps organize paged:
+
Paginator, который помогает организовать постраничный вывод:
 
<source lang="python">>>> from django.core.paginator import Paginator
 
<source lang="python">>>> from django.core.paginator import Paginator
>>> Objects = ['django', 'python', 'mysql', 'apache']
+
>>> objects = ['django', 'python', 'mysql', 'apache']
>>> P = Paginator (objects, 2)
+
>>> p = Paginator(objects, 2)
>>> Page1 = p.page (1)
+
>>> page1 = p.page(1)
>>> Page1.object_list
+
>>> page1.object_list
['Django', 'python'] </ source>
+
['django', 'python']</source>
Since most of our objects are stored in the database,
+
Поскольку большинство наших объектов хранятся в базе данных,
Django also offers class QuerySetPaginator, which takes no list, and many objects from the database.
+
Django также предлагает класс QuerySetPaginator, который принимает не список, а множество объектов из СУБД.
*; Sitemaps
+
*; Карты сайта
Want to have your site properly indexed by search
+
Хотите, чтобы ваш сайт правильно индексировался поисковыми
machines? You need to create his map! Django will help
+
машинами? Необходимо создать его карту! Django поможет и
here, and the function django.contrib.sitemaps.ping_google «cause»
+
здесь, а функция django.contrib.sitemaps.ping_google «заставит»
Google to update the index for your website.
+
Google обновить индексы для вашего сайта.
; * Managing multiple sites
+
*; Управление несколькими сайтами
One of the problems with which copes Django, is
+
Одной из задач, с которой успешно справляется Django, является
control of several similar sites on the subject of a
+
управление несколькими схожими по тематике сайтами из одной
installation. The project was originally designed as a platform for news portals, news, and one could appear
+
инсталляции. Проект первоначально разрабатывался как платформа для новостных порталов, и одна новость могла появиться
on multiple resources.
+
сразу на нескольких ресурсах.
*; To help designers
+
*; В помощь дизайнерам
Load the module templates to help designers:
+
Подгрузив к шаблонам модуль помощи дизайнерам:
 {% Load webdesign%}
+
{% load webdesign %}
you get at your disposal tag {% lorem%}, with
+
вы получите в свое распоряжение тэг {% lorem %}, с помощью
which you can display certain Latin phrase «lorem
+
которого можно выводить известную латинскую фразу «lorem
ipsum ... »to fill the template" fish. "
+
ipsum ...» для заполнения шаблонов «рыбой».
; * And more
+
*; И более того
Django has a lot of other "goodies" that are very
+
Django содержит много других «вкусностей», которые очень
well described in the accompanying documentation in English
+
хорошо описаны в прилагающейся документации на английском
language.
+
языке.
| Width =}}
+
|Ширина=}}

Текущая версия на 19:53, 3 июня 2015

Содержание

[править] Финальные штрихи

ЧАСТЬ 4 Уроки Django подходят к концу, наступает пора экзаменов – если не для вас, то для приложений уж точно. Никита Шультайс (http://shultais.ru) разберется с тестированием и пробежится по другим возможностям этого каркаса.

Новостная лента готова – но оправдает ли она ожидания пользователей? Ответ на этот вопрос может дать тестирование, лучше всего – в реальных условиях; но какие-то основные вещи можно проверить еще на этапе разработки. Если вы успели заглянуть в учебник Rails, то уже знаете о методологии TDD. Мы, однако, пойдем другим путем, и будем тестировать приложение не до написания, а после.

Дело это – серьезное и сложное, так как нам нужно учитывать взаимодействие с БД, компиляцию шаблонов, обработку GET- и POST-запросов и прочие компоненты системы: сбой в любом из них может вызвать нарушить работу всего сайта. К данной задаче можно подойти с двух сторон:

  • Тестирование в браузере. Речь идет о программах Twill (http://twill.idyll.org) и Selenium (http://selenium.openqa.org): они «запоминают» последовательность ваших действий для каждой страницы, а затем воспроизводят ее по запросу. Например, можно ввести в поля формы заведомо неверные данные, получить ожидаемую ошибку и повторять этот тест при каждом серьезном изменении в коде вашего приложения.
  • Тестирование на сервере. И тут Django не оставляет нас на произвол судьбы, предлагая сразу два варианта: doctest (тестирование через документацию) и unittest (модульное тестирование), плюс специальный клиент для отправки GET- и POST-запросов.

Если вы давно программируете на Python, то вам, наверное, будет ближе doctest, а мигрантам из мира Java скорее придется по вкусу unittest. Никаких ограничений на их использование не накладывается: вы можете выбрать одну систему или применять обе сразу. Мы же остановимся на doctest.

[править] Документируй это!

Строка документации в Python – это обычный текст, размещаемый после определения функции или класса непосредственно в исходном коде. Она же предоставляет содержимое для атрибута __doc__. Как правило, ее помещают в тройные кавычки ("""), что позволяет вводить сложные конструкции с переносами строк, отступами, теми же кавычками и... тестами. Этим мы и воспользуемся.

Тесты могут находится в файлах моделей (models.py) – для проверки последних – и в специальных файлах tests.py, расположенных в директории приложения. К примеру, создайте файл news/tests.py такого содержания:

  1. # -*- coding: utf-8 -*-
  2.  
  3. """
  4. >>> from news.models import News
  5. >>> from datetime import datetime
  6. >>> news = News(title="Заголовок",description="Описание",pub_date=datetime.now(), text="Текст")
  7. >>> news.save()
  8. >>> news = News.objects.get(pk=1)
  9. >>> print news.title.encode('utf-8')
  10.  Заголовок
  11. """

В строке 1 задается кодировка, а начиная с третьей идет сам тест. Заметьте, что каждая строка начинается с трех знаков «больше» (>>>), как в интерактивном режиме работы Python. В строке 10 этих знаков нет, так как она содержит ожидаемый вывод команды print со строки 9.

(thumbnail)
Рис. 1. Тест пройден удачно!

Перед тем, как запустить тест, в settings.py нужно добавить строку

TEST_DATABASE_CHARSET="UTF8"

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

python manage.py test news

после выполнения которой вы увидите примерно то, что показано на рис. 1.

Сообщения похожи на появляющиеся во время создания таблиц при первой установке, но теперь все происходит в тестовой БД. В конце отображается число выполненных тестов, их результаты и уведомление об уничтожении тестовой базы. Мы проверяли наше приложение (news), но, как вы помните, Django содержит несколько собственных приложений и представлений (например, «админку») – и они тоже снабжаются своими тестами. Чтобы выполнить их все, нужно ввести команду:

python manage.py test

добавив предварительно в главный файл URL-карт следующие строки:

urlpatterns += patterns('django.contrib.auth.views',
url(r'^auth/password_reset/$','password_reset'),
)

Здесь мы подключаем одно из встроенных представлений, предназначенное для восстановления пароля. Это необходимо, так как при тестировании всего проекта происходит обращение по указанному URL, и если представление не определено, тест будет провален. Кстати, вы тоже можете попробовать password_reset в работе (рис. 2).

(thumbnail)
Рис. 2. Забыли пароль? Это проблемы Django!

[править] Имитатор Сети

Количество тестов уже достигло шести, но помимо создания и извлечения объектов из базы, нам нужно проверить реакцию на GET- и POST-запросы. Как вы знаете, для этих целей существует специальный клиент: он эмулирует запрос и возвращает переменные, которые передаются в шаблон для данного URL. Добавьте в файл tests.py после строки 10 следующий код:

  1. >>> from django.contrib.auth.models import User
  2. >>> user = User.objects.create_user('django_guru', 'user@example.com', 'password')
  3. >>> user.save()
  4. >>> from django.test.client import Client
  5. >>> c = Client()
  6. >>> c.login(username='django_guru',password=“password”)
  7. True
  8. >>> response = c.get('/news/1/')
  9. >>> response.status_code
  10. 200
  11. >>> print response.context[0]['user'].username
  12. django_guru
  13. >>> response = c.post('/news/1/',{'username':“testuser”,'text':»»})
  14. >>> response.status_code
  15. 200
  16. >>> response = c.post('/news/1/',{'username':“testuser”,'text':»Comment text»})
  17. >>> response.status_code
  18. 302
  19. >>> from news.models import Comment
  20. >>> comment = Comment.objects.get(news=news)
  21. >>> print comment.text
  22. Comment text

Разберемся, что здесь происходит. В строках 11–13 мы создаем нового пользователя (django_guru), а в 14–15 – тестовый клиент. В строке 16 django_guru авторизуется, и отныне все действия в системе будут совершаться от его имени. В строке 18 мы переходим на страницу нашей первой новости, передав средствами клиента GET-запрос. Для проверки, что нам это удалось, мы изучаем код ответа сервера (строка 19) – он должен равняться 200, или тест будет провален. Затем (строки 21–22), чтением дополнительных данных ответа, мы убеждаемся, что запрос сделал зарегистрированный пользователь django_guru. Теперь самое время оставить комментарий – не зря же мы авторизовались? В строке 23 генерируется POST-запрос (второй аргумент метода post() – словарь отсылаемых на сервер данных). Обратите внимание, что значение ключа text оставлено пустым, а значит, комментарий не добавится, однако сервер по-прежнему должен возвращать код 200 (строка 25). А вот в строке 26 мы передаем все необходимые данные, и так как после создания комментария нас перенаправляют на страницу новости, код ответа должен быть равен 302 (Требуемый URL перемещен). В строках 29–32 проверяется, что комментарий был действительно добавлен: мы сравниваем его текст с исходным значением. Уфф... тест пройден.

[править] Действительно простая синдикация

Какой новостной сайт без ленты? RSS и/или Atom есть везде – будут и у нас, а Django нам в этом поможет. Откройте главный файл URL-карт и добавьте в его конец следующие строки:

  1. from feeds import LatestNews
  2.  
  3. feeds = {
  4. 'latest': LatestNews,
  5. }
  6. urlpatterns += patterns('',
  7. (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
  8. {'feed_dict': feeds}),
  9. )

Далее нужно приготовить ленту LatestNews, которую мы импортируем в строке 1. Создайте в корне проекта каталог feeds с файлом __init__.py следующего содержания:

  1. # -*- coding: utf-8 -*-
  2.  
  3. from django.contrib.syndication.feeds import Feed
  4. from news.models import News
  5. from django.contrib.syndication.feeds import FeedDoesNotExist
  6.  
  7. class LatestNews(Feed):
  8. title = "Последние новости нашего сайта"
  9. description = "Последние события на сайте mysite.com"
  10. link = "http://127.0.0.1:8000/news/"
  11.  
  12. def items(self):
  13. return News.objects.order_by("-pub_date")[:5]
  14.  
  15. def item_link(self, obj):
  16. from django.core.urlresolvers import reverse
  17. return 'http://127.0.0.1:8000%s' % reverse('news.news_detail',kwargs={"news_id":obj.pk})
(thumbnail)
Рис. 3. Firefox предлагает подписаться на обновления нашего новостного сайта – теперь держитесь!

Поля title, description и link класса LatestNews являются обязательными и отвечают за одноименные элементы RSS. Метод items() передает в ленту требуемые объекты, а item_link() отвечает за ссылку на сайт. Теперь создайте каталог feeds в media/templates и добавьте в него два файла, latest_description.html и latest_title.html: они будут отвечать за вид новостной ленты. В lates_description.html напишите:

{{ obj.description }}

а в latest_title.html:

[{{ obj.pub_date|date:"d.m.Y" }}] {{ obj.title }}

Объект obj представляет собой запись из выборки, которую мы возвращаем в строке 13 файла feeds/__init__.py. Пройдя по адресу http://127.0.0.1:8000/feeds/latest/, мы увидим предложение Firefox сохранить ленту новостей. Пользователи KDE, вероятно, предпочтут Akregator – с ним тоже нет никаких проблем (рис. 3, 4)

[править] Общие представления

Чтобы облегчить жизнь web-разработчика, Django включил большое число представлений для решения стандартных задач. Так, добавив в главный файл URL-карт следующий код:

from django.views.generic.list_detail import object_list
from news.models import News
urlpatterns += patterns('',
('^lastnews/$', object_list, {
'queryset': News.objects.all().order_by('-pub_date')[:10],
'template_name':'news/last_news.html',
'template_object_name':'last_news'})
)

а также заменив в файле news/templates/news/last_news.html

{% for news in last_news %}

на

{% for news in last_news_list %}

мы сможем просматривать последние новости по адресу http://127.0.0.1:8000/lastnews/, не вызывая представление news.last_news. Чтобы сделать доступными оба варианта, нужно найти в представлении news.last_news строку

"last_news":news,

и заменить ее на

"last_news_list":news,

Как вы уже догадались, общее представление object_list предназначено для работы со списком объектов. Еще есть представления для вывода объектов в зависимости от даты (django.views.generic.date_based.*), что позволяет очень просто создавать архивы записей:

  • archive_index – вывод последних объектов, добавленных в базу данных;
  • archive_{year,month,week,day,today} – вывод всех объектов за определенный год, месяц, неделю, день или за сегодня;
  • object_detail – вывод одного объекта за определенный день.

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

[править] Добавляем переменные на лету

В глубинах Django скрываются глобальные контекстные процессоры, основная задача которых – снабжать шаблоны переменными и объектами. Узнать, какие из них подключены, можно в кортеже TEMPLATE_CONTEXT_PROCESSORS в файле settings.py. Например, у нас сейчас работают следующие процессоры:

  • auth – информация о пользователе: объект user, его права доступа и сообщения, которые были ему отправлены;
  • i18n – сведения о текущем языке сайта и клиента;
  • request – данные о запросе.

Кроме них, существует еще процессор debug, передающий в шаблон данные о выполненных SQL-запросах, плюс мы можем написать свой собственный! Для этого создадим в корне нашего проекта каталог processors и добавим в него два файла: __init__.py и context_processors.py. Последний должен содержать такой код:

import settings
def site_settings(request):
return {'SETTINGS': settings}

Чтобы подключить процессор, просто перечислите его в кортеже TEMPLATE_CONTEXT_PROCESSORS. Проверим работоспособность: добавим в шаблон news.html следующее:

{{ SETTINGS.TIME_ZONE }}

Конечно, TIME_ZONE можно заменить на любую другую переменную, определенную в settings.py.

[править] Сам себе фильтр

С фильтрами мы познакомились еще в LXF105, однако часто возникают ситуации, когда поставляемых с Django вариантов недостаточно. Чтобы написать свой собственный фильтр, создайте в корне проекта каталог templatetags/ и добавьте в него файлы __init__.py и filters.py. В filters.py напишите:

  1. from django import template
  2.  
  3. register = template.Library()
  4.  
  5. @register.filter
  6. def exp(value, arg):
  7. if value.isdigit() and arg.isdigit():
  8. return int(value)**int(arg)
  9. else:
  10. return '<span style=“color:red”>Error</span>'
  11. exp.is_safe = True

Мы создали фильтр exp, который получает значение и показатель степени и возводит одно в другое; если аргументы не являются числами, генерируется ошибка. В строке 5 мы регистрируем фильтр в системе с помощью декоратора. Строка 11 указывает, что exp может возвращать HTML-код. Поскольку (в целях безопасности) он автоматически экранируется (< и > заменяются на &lt; и &gt; и т.д.), то, желая видеть чистый HTML, мы должны запретить такое поведение вручную. Следующим шагом является подгрузка библиотеки фильтров в шаблон, для чего нужно добавить в него следующую строку:

{% load filters %}

Вообще-то Django ищет созданные библиотеки шаблонов в корне приложения, поэтому наш фильтр пока не будет доступен. Это не очень удобно, особенно если мы хотим использовать один и тот же фильтр во многих приложениях. Решение – создать для проекта единую библиотеку, а в приложения помещать лишь символьные ссылки на нее.

ln -s /var/www/myproject/templatetags/ /var/www/myproject/news/

Теперь проверим работу фильтра, добавив в какой-нибудь шаблон строку.

{{ "4"|exp:"4" }}

Во время компиляции она будет заменена на 256. Если же мы напишем

{{ "a"|exp:"4" }}

то увидим слово «Error», выделенное красным цветом. Кстати, если бы мы не указали в строке 11 фильтра exp.is_safe= True, можно было бы просто применить фильтр safe прямо в шаблоне:

{{ "a"|exp:"4"|safe }}

После регистрации фильтра в системе, информация о нем становится доступной по адресу http://127.0.0.1:8000/admin/doc/filters/ (рис. 4)

(thumbnail)
Рис. 4. Система любезно подскажет, как использовать созданный вами фильтр.

[править] Компоненты

Если нам надо выполнить какие-либо действия до или после того, как будет вызвано представление, либо в случае ошибки, можно создать свой компонент (middleware) или воспользоваться поставляемым с Django. Мы уже делали это, когда изучали кэширование (LXF107). Напомню, что в файле settings.py есть кортеж MIDDLEWARE_CLASSES, который перечисляет компоненты, задействованные в проекте. У нас это:

  • django.middleware.common.CommonMiddleware Решает общие задачи: нормализует URL (добавляет префикс www и завершающий /), запрещает доступ к сайту определенным роботам, взаимодействует с Etag.
  • django.contrib.sessions.middleware.SessionMiddleware Это сессии.
  • django.contrib.auth.middleware.AuthenticationMiddleware А это – авторизация.
  • django.middleware.doc.XViewMiddleware Используется для автоматического документирования Django.
  • django.middleware.locale.LocaleMiddleware Интернационализация.

Помимо перечисленных выше, в Django доступны следующие компоненты (django.middleware.*):

  • gzip.GZipMiddleware Сжатие отправляемой страницы для экономии трафика.
  • http.ConditionalGetMiddleware Поддержка условных GET-запросов для работы с Last-Modified и Etag.
  • http.SetRemoteAddrFromForwardedFor Обратное проксирование.
  • cache.CacheMiddleware Тот самый кэш, с которым мы сталкивались на прошлом уроке.
  • transaction.TransactionMiddleware Компонент для включения в SQL-запросы транзакционных конструкций: COMMIT, ROLLBACK.

Заметьте, что не все базы данных поддерживают транзакции.

И, наконец, django.contrib.csrf.middleware.CsrfMiddleware, защищающее от CSRF-атак.

По сложившейся уже традиции, рассмотрим, как написать свой собственный компонент. С точки зрения программиста, это просто класс Python, имеющий ряд методов, вызываемых Django в определенные моменты времени. Первым из них является конструктор __init__(self), регистрирующий компонент в системе. Дальше следуют методы, определяющие порядок выполнения кода:

  • process_request() – запускается после того, как поступил запрос,но перед тем как Django начнет искать запрашиваемый адрес в URL-картах;
  • process_view() – отрабатывает, когда конкретное представление уже определено, но еще не запущено;
  • process_response() – выполняется после представления.

Используется для сжатия сгенерированного HTML. process_exception() – вызывается, если что-то пошло не так или было возбуждено необработанное исключение.

Вот, в сущности, и все. Впрочем, нет – взгляните на врезку И прочая, прочая, прочая, почитайте документацию или свободную книгу о Django – Django Book (http://www.djangobook.com); если же вам больше по душе русский, советую заглянуть на http://cargo.caml.ru/djangobook. Наконец, примените полученные знания на практике – и дайте нам знать, если у вас получится что-то действительно стоящее!


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