<?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=Gordano</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=Gordano"/>
		<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/Gordano"/>
		<updated>2026-05-13T09:10:48Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF106:Django</id>
		<title>LXF106:Django</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF106:Django"/>
				<updated>2009-10-17T16:53:05Z</updated>
		
		<summary type="html">&lt;p&gt;Gordano: Убрал нумерацию строк в листенге - т.к. сильно затрудняяет форматирование при вставке в проект&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;: '''''Django''''' Разрабатываем динамические web-приложения современным способом[[Категория:Учебники]]&lt;br /&gt;
&lt;br /&gt;
==Личная блогосфера==&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Django}}&lt;br /&gt;
&lt;br /&gt;
: '''ЧАСТЬ 2''' Новостной портал из прошлого номера журнала легко превратить в мини-блог, предоставив посетителям возможность оставлять комментарии. Но что делать с троллями и спамерами? '''Никита Шультайс''' (http://shultais.ru) во всем разберется.&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы научились создавать простые ''Django''-приложения, добавили несколько записей в базу данных и вывели на сайт заголовок, дату и описание для последних десяти новостей. А как быть с теми, кто пожелает прочитать текст&lt;br /&gt;
сообщения целиком?&lt;br /&gt;
&lt;br /&gt;
Правильно, нужно снова создавать представления и шаблоны.&lt;br /&gt;
Но для начала, усовершенствуем наши URL-карты.&lt;br /&gt;
&lt;br /&gt;
===Добавим гибкости===&lt;br /&gt;
&lt;br /&gt;
Откройте файл '''urls.py''' (как вы помните, именно он устанавливает&lt;br /&gt;
соответствие между URL-адресами и представлениями) и замените строку&lt;br /&gt;
&lt;br /&gt;
 (r'^news/', 'news.views.last_news')&lt;br /&gt;
&lt;br /&gt;
на&lt;br /&gt;
&lt;br /&gt;
 (r'^news/', include('news.urls'))&lt;br /&gt;
&lt;br /&gt;
Теперь при переходе к '''news/''' будут подгружаться URL-карты,&lt;br /&gt;
относящиеся к приложению. Это позволит нам работать с новостной системой, не выходя за рамки директории news. Далее, нужно&lt;br /&gt;
составить URL-карты приложения: создайте файл '''news/urls.py''' следующего содержания:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from django.conf.urls.defaults import *&lt;br /&gt;
urlpatterns = patterns('news.views',&lt;br /&gt;
url(r'^$','last_news',name = 'news.last_news'),&lt;br /&gt;
url(r'^(?P&amp;lt;news_id&amp;gt;\d+)/$','news_detail',name = 'news.news_detail'),&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Что происходит при обращении к http://mysite.com/news/? Сначала часть URL ('''news/''') ищется в главном файле URL-карт, где&lt;br /&gt;
обнаруживается соответствие. Затем система считывает URL-карты,&lt;br /&gt;
отвечающие за конкретное приложение (благодаря '''include('news.urls')''') и продолжает поиск, откинув уже найденный шаблон. Так как&lt;br /&gt;
после '''news/''' ничего нет, ''Django'' остановится в строке 3 файла '''news/urls.py''' и выполнит представление '''news.views.last_news''', которое мы&lt;br /&gt;
создали на прошлом уроке.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим '''news/urls.py''' подробнее. Во второй строке есть интересная запись – '''news.views''', которая указывает ''Django'', что нужно&lt;br /&gt;
задействовать представления из одноименного модуля; это позволяет сэкономить место при наборе URL-карт и облегчает чтение&lt;br /&gt;
кода. Строки 3 и 4 – это URL-карты особого формата. Они обернуты функцией '''url()''', принимающей три (точнее сказать – до пяти)&lt;br /&gt;
аргументов:&lt;br /&gt;
&lt;br /&gt;
* первый (позиционный обязательный) – регулярное выражение;&lt;br /&gt;
* второй (позиционный обязательный) – имя представления, которое будет выполняться;&lt;br /&gt;
* третий (именованный необязательный) – имя URL-карты. Оно должно быть уникальным не только для приложения, но и для всего проекта, и в нашем случае состоит из двух частей: имени приложения и представления (это не единственный вариант). Часто возникают ситуации, когда одно представление обслуживает несколько URL-адресов, но имя каждой URL-карты всё равно должно быть уникальным. Скажем, если представление view может добавлять или изменять объекты, в зависимости от URL, то карты могут называться '''app.view.add''' и '''app.view.change'''.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Заголовок=Скорая помощь|Содержание=Если вы взглянете на наши модели, то увидите, что поля первичного ключа – '''id''' – в них&lt;br /&gt;
нет, однако в примере с тегом '''url''' мы используем '''news.id''', как ни в чем не бывало. Все верно – ''Django'' сам создает первичные ключи для каждой модели.|Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на конструкцию ('''?P&amp;lt;news_id&amp;gt;\d+''') в строке 4.&lt;br /&gt;
Она совпадает с числом ('''\d+'''), захватывает его и помещает в переменную '''news_id''', которая затем передается в представление.&lt;br /&gt;
&lt;br /&gt;
Хотя картам и не обязательно давать имена, это очень сильно упрощает жизнь&lt;br /&gt;
разработчика и делает приложение переносимым. Поэтому откройте файл '''news/templates/news/last_news.html''' и измените&lt;br /&gt;
строку:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;strong&amp;gt;{{ news.title }}&amp;lt;/strong&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;strong&amp;gt;&lt;br /&gt;
   &amp;lt;a href=”{% url news.news_detail news_id=news.id %}”&amp;gt;{{ news.title }}&amp;lt;/a&amp;gt;&lt;br /&gt;
 &amp;lt;/strong&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве значения атрибута '''href''' мы вставили тег '''url''' системы шаблонов&lt;br /&gt;
''Django''. Ему передаются имена URL-карты&lt;br /&gt;
и объявленной нами переменной – '''news_id'''. Значение '''news_id''' присваивается первичному ключу новости, которую хотим&lt;br /&gt;
просмотреть.&lt;br /&gt;
&lt;br /&gt;
Теперь, когда ''Django'' будет компилировать наш шаблон, '''{% url news.news_detail news_id=news.id %}''' заменится на http://mysite.com/news/1/ для новости с номером 1, и так далее. Если же вы решите модифицировать URL-&lt;br /&gt;
карты, например, переименовав news/ в главном файле URL-карт&lt;br /&gt;
в '''supernews/''', то система автоматически скорректирует все ссылки,&lt;br /&gt;
и сайт продолжит работать. Не забудьте только отредактировать&lt;br /&gt;
файл '''media/templates/index.html''', поправив:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;a href=”/news/”&amp;gt;News&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;a href=”{% url news.last_news %}”&amp;gt;News&amp;lt;/a&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вы решите опробовать возможность автоматической генерации URL, не дожидаясь конца урока, то потребуется также добавить в файл '''news/views.py''' представление-заглушку для нового типа URL,&lt;br /&gt;
&lt;br /&gt;
 def news_detail(requets,news_id):&lt;br /&gt;
   pass&lt;br /&gt;
&lt;br /&gt;
В противном случае автогенерация работать не будет.&lt;br /&gt;
&lt;br /&gt;
===Создаем форму===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF106_79_1.jpg|Рис. 1|300px]]Рис.1. Вот что должно получиться в итоге.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Продолжим развитие нашего приложения. Сейчас мы создадим&lt;br /&gt;
представление и шаблон, с помощью которого можно просматривать детали новости, а также добавлять комментарии. Первым&lt;br /&gt;
делом нужно реализовать форму для комментариев (рис.1), и,&lt;br /&gt;
как вы могли догадаться, ''Django'' поможет нам в этом непростом&lt;br /&gt;
деле. Дистрибутив ''Django'' содержит целых две системы обработки&lt;br /&gt;
форм: '''forms''' (старую) и '''newforms''' (новую). Мы будем пользоваться&lt;br /&gt;
последней, так как она более удобна и имеет больше возможностей. К тому же в версии 1.0 разработчики удалят старую библио&lt;br /&gt;
теку, оставив только '''newforms''' (которая будет переименована в&lt;br /&gt;
'''forms''').&lt;br /&gt;
&lt;br /&gt;
Формы очень удобно хранить в файле '''forms.py''' в директории приложения. Создайте его и наберите код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; &amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
from django import newforms as forms&lt;br /&gt;
class CommentForm(forms.Form):&lt;br /&gt;
username = forms.CharField(label=”Имя”,required=True,&lt;br /&gt;
    widget=forms.TextInput(attrs={&lt;br /&gt;
       'size':'30',&lt;br /&gt;
       'maxlength':'255'}))&lt;br /&gt;
text = forms.CharField(label=”Текст”,required=True,&lt;br /&gt;
    widget=forms.Textarea())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Заголовок=Все еще сомневаетесь?|Содержание=Приведем два основных преимущества отделения URL-карт уровня приложений от главной карты сайта:&lt;br /&gt;
&lt;br /&gt;
* '''Переносимость''' Теперь, если мы хотим добавить наше приложение в другой проект, нужно только скопировать директорию с ним в корень проекта, вписать его в '''INSTALLED_APPS''' и включить '''news/urls.py''' в главный файл '''urls.py'''. Если автор приложения расширит функциональность (например, добавит версию для печати), достаточно будет обновить файлы внутри директории '''news''', не заботясь о добавлении или изменении URL-карт.&lt;br /&gt;
* '''Удобная работа с картами'''. В реальных проектах количество приложений может достигать 20 и больше, и каждое из них может содержать 10–20 внутренних карт. Если бы мы оформляли все URL-карты в одном файле, то его размер составил бы около 400 строк, а следовательно, возросла бы вероятность ошибки.|Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
Каждая форма представлена классом ''Python'', унаследованным&lt;br /&gt;
от '''forms.Form'''. Она содержит набор полей, являющихся объектами&lt;br /&gt;
класса '''forms.*Field'''. Так, в строках 4-7 определяется поле '''username'''&lt;br /&gt;
типа '''CharField''' – символьное. Атрибут '''required''' указывает, что мы&lt;br /&gt;
не можем оставить его пустым. Далее следует определение «виджета», то есть органа управления, который будет отображаться на&lt;br /&gt;
web-странице. Виджет связан с определенным элементом '''HTML'''-формы, например, '''&amp;lt;select&amp;gt;, &amp;lt;input&amp;gt;''' или '''&amp;lt;textarea&amp;gt;'''. Каждый класс&lt;br /&gt;
поля имеет свой стандартный виджет, но мы можем переопределить или расширить его, добавив дополнительные атрибуты.&lt;br /&gt;
Виджетом по умолчанию для '''CharField''' является '''TextInput (&amp;lt;input type=»text»&amp;gt;)''', здесь мы задаем ему атрибуты '''size''' и '''maxlength'''. В&lt;br /&gt;
строках 8-9 определяется поле '''text''', которое также является символьным, но, поскольку одна строка плохо подходит для ввода&lt;br /&gt;
комментария, мы назначаем '''text''' виджет '''Textarea()''', соответствующий '''HTML'''-тегу '''&amp;lt;textarea&amp;gt;'''. Обратите внимание на атрибуты '''label:''' они содержат поясняющий текст, который выводится около элемента экранной формы. Так как мы используем кириллицу, необходимо указать кодировку – это делается в первой строке. Я предпочитаю UTF-8.&lt;br /&gt;
&lt;br /&gt;
Теперь пришло время заменить и нашу заглушку (если, конечно,&lt;br /&gt;
вы ее создали):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def news_detail(request, news_id):&lt;br /&gt;
news = News.objects.get(pk=news_id)&lt;br /&gt;
if request.method == 'POST':&lt;br /&gt;
     form = CommentForm(request.POST)&lt;br /&gt;
     if form.is_valid():&lt;br /&gt;
        comment = Comment(&lt;br /&gt;
           news=news,&lt;br /&gt;
           username = form.cleaned_data['username'],&lt;br /&gt;
           text = form.cleaned_data['text'])&lt;br /&gt;
         comment.save()&lt;br /&gt;
         return HttpResponseRedirect(&lt;br /&gt;
             reverse('news.news_detail',kwargs={'news_id':news_id}))&lt;br /&gt;
 else:&lt;br /&gt;
      form = CommentForm()&lt;br /&gt;
&lt;br /&gt;
 comments = Comment.objects.filter(news=news).order_by(“pub_ date”,”id”)&lt;br /&gt;
 comment_count = comments.count()&lt;br /&gt;
&lt;br /&gt;
 template = get_template(“news/news_detail.html”)&lt;br /&gt;
 context = RequestContext(request, {&lt;br /&gt;
      “news”:news,&lt;br /&gt;
      “form”:form,&lt;br /&gt;
      “comment_count”:comment_count,&lt;br /&gt;
      “comments”:comments&lt;br /&gt;
 })&lt;br /&gt;
 return HttpResponse(template.render(context))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сразу стоит обратить внимание на то, что в представление передается дополнительный аргумент '''news_id''', имя которого совпадает с идентификатором переменной, захватываемой при обработке&lt;br /&gt;
регулярного выражения в файле '''news/urls.py'''. Во второй строке&lt;br /&gt;
мы извлекаем новость, а так как нам нужен только один объект,&lt;br /&gt;
то используем для этого функцию '''get()''', передавая ей '''news_id'''&lt;br /&gt;
в качестве именованного аргумента '''pk''' ('''Primary Key''', первичный ключ). Дальше следуют два блока: для '''POST-''' (строки 4-12), и&lt;br /&gt;
'''GET-'''запросов (14). В строке 3 проверяется, как именно произошло&lt;br /&gt;
обращения к данному URL. В случае '''GET''' мы просто создаем объект&lt;br /&gt;
формы с пустыми полями.&lt;br /&gt;
&lt;br /&gt;
Если же данные были получены посредством запроса '''POST''', они&lt;br /&gt;
передаются в форму. Далее идет проверка на корректность (строка&lt;br /&gt;
5): мы убеждаемся, что заполнены все поля. В случае успеха создается объект комментария. Первый параметр – это новость, к которой&lt;br /&gt;
он относится, аргументам '''username''' и '''text''' присваиваются очищенные&lt;br /&gt;
(то есть преобразованные к определенному типу: '''unicode''' для текста,&lt;br /&gt;
'''datetime''' для даты и так далее) данные из полей формы. В 10-й строке&lt;br /&gt;
объект сохраняется в БД, а в строках 11–12 мы осуществляем перенаправление. Функция '''reverse''' – это аналог тега url в шаблонах. Она принимает имя URL-карты, а в словаре '''kwargs''' должны содержаться требуемые аргументы, причем переменной '''news_id''' присваивается номер&lt;br /&gt;
текущей новости... Проще говоря, мы обновляем страницу. Если же&lt;br /&gt;
проверка в строке 5 не проходит, то мы автоматически отправляемся к&lt;br /&gt;
строке 15 с формой, где уже заполнены некоторые поля, а для пустых&lt;br /&gt;
созданы сообщения об ошибках.&lt;br /&gt;
&lt;br /&gt;
Обратимся к строкам 16 и 17. В первой мы извлекаем все комментарии, относящиеся к новости, а во второй получаем их количество, причем функция '''count()''' генерирует '''SQL'''-конструкцию '''COUNT''',&lt;br /&gt;
которая работает очень быстро.&lt;br /&gt;
&lt;br /&gt;
Строки 19-26 рассматривались на прошлом уроке, и сейчас мы&lt;br /&gt;
не будем на них останавливаться. Лучше рассмотрим шаблон '''news/templates/news/news_detail.html''' – он может иметь такой вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{% extends “index.html” %}&lt;br /&gt;
&lt;br /&gt;
{% block application %}&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;h1&amp;gt;{{ news.title }}&amp;lt;/h1&amp;gt;&lt;br /&gt;
    &amp;lt;p&amp;gt; {{ news.text }} &amp;lt;/p&amp;gt;&lt;br /&gt;
{% if comment_count %}&lt;br /&gt;
     &amp;lt;h3&amp;gt;Комментариев: {{ comment_count }}&amp;lt;/h3&amp;gt;&lt;br /&gt;
     {% for comment in comments %}&lt;br /&gt;
      &amp;lt;div&amp;gt;&lt;br /&gt;
      &amp;lt;strong&amp;gt;{{ comment.username }}&amp;lt;/strong&amp;gt; пишет:&amp;lt;br/&amp;gt;&lt;br /&gt;
      {{ comment.text }}&amp;lt;br/&amp;gt;&lt;br /&gt;
      Дата {{ comment.pub_date|date:”d.m.Y” }}&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
    {% endfor %}&lt;br /&gt;
{% else %}&lt;br /&gt;
     &amp;lt;h3&amp;gt;Комментариев нет&amp;lt;/h3&amp;gt;&lt;br /&gt;
{% endif %}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Оставить комментарий:&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;form action=”.” method=”POST”&amp;gt;&lt;br /&gt;
&amp;lt;table&amp;gt;{{ form }}&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;input type=”submit”/&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{% endblock %}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на строку 7, с которой начинается новый для нас тег – '''{% if %}'''. Он принимает логическую (а поскольку в ''Python'' все числовые значения и строки, которые не равны нулю и не пусты, эквивалентны True, то практически любую) переменную. В строке 17&lt;br /&gt;
расположена вторая часть тега – альтернативный блок '''{% else %}''' и,&lt;br /&gt;
наконец, в строке 19 тег закрывается. Разумеется, альтернативный&lt;br /&gt;
блок можно опустить.&lt;br /&gt;
&lt;br /&gt;
Хотя ''Django'' берет на себя бремя генерации форм, некоторую&lt;br /&gt;
часть кода приходится писать вручную. Так, в строке 22 мы определяем форму, а в строке 23 создаем таблицу, в которую она будет&lt;br /&gt;
помещена. Дело в том, что по умолчанию при вызове объекта формы все виджеты оборачиваются в '''&amp;lt;nowiki&amp;gt;&amp;lt;tr&amp;gt; и &amp;lt;td&amp;gt;&amp;lt;/nowiki&amp;gt;'''. Это поведение можно&lt;br /&gt;
исправить, заменив '''form''' на '''form.as_ul''' или '''form.as_p''', которые которые возвращают ее в виде ненумерованного списка '''&amp;lt;nowiki&amp;gt;(&amp;lt;ul&amp;gt;)&amp;lt;/nowiki&amp;gt;''' и параграфов '''&amp;lt;nowiki&amp;gt;(&amp;lt;p&amp;gt;)&amp;lt;/nowiki&amp;gt;''', соответственно. Кнопка для отправки формы создается&lt;br /&gt;
в строке 24.&lt;br /&gt;
&lt;br /&gt;
Теперь, когда мы создали шаблон и представление для просмотра текста новости и добавления комментариев, осталось только&lt;br /&gt;
импортировать необходимые классы и функции в представление&lt;br /&gt;
'''news/views.py''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
   from news.models import News&lt;br /&gt;
   from news.forms import CommentForm&lt;br /&gt;
   from django.http import HttpResponseRedirect&lt;br /&gt;
   from django.core.urlresolvers import reverse&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Не забудьте, что импортировать классы и функции нужно до их&lt;br /&gt;
первого использования.&lt;br /&gt;
&lt;br /&gt;
===Плохой песик, плохой!===&lt;br /&gt;
&lt;br /&gt;
Когда ваши новости комментируют объективно – это прекрасно,&lt;br /&gt;
но мир неидеален и пока не искоренены спам и флуд, вам придется модерировать сообщения, оставленные посетителями. Наша&lt;br /&gt;
система не поддерживает пре-модерацию; конечно, в реальных&lt;br /&gt;
проектах так поступать не стоит. Но и у нас не всё потеряно – мы&lt;br /&gt;
можем:&lt;br /&gt;
&lt;br /&gt;
* Модерировать комментарии из административного интерфейса&lt;br /&gt;
* Делать это прямо с сайта.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF106_81_1.jpg|Рис. 2|300px]]Рис. 2. Пользователи и группы ''Django''.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Первый вариант настолько прост, что мы даже не будем на&lt;br /&gt;
нем останавливаться, но прежде чем перейти ко второму случаю,&lt;br /&gt;
поговорим о системе прав ''Django''. С главной страницы «админки»&lt;br /&gt;
можно перейти в разделы управления пользователями и группами (рис.2).&lt;br /&gt;
&lt;br /&gt;
Каждый пользователь и группа могут иметь определенные&lt;br /&gt;
права доступа, которые описываются в моделях. По умолчанию,&lt;br /&gt;
модель предоставляет три разрешения: добавить, изменить и удалить объект из базы данных. Если вы перейдете на страницу редактирования пользователя в «админке», то в разделе '''Permissions &amp;gt; User permissions''' увидите список прав доступа, причем в левой&lt;br /&gt;
части ('''Available user permissions''') указываются всевозможные права,&lt;br /&gt;
известные системе, а в правой ('''Chosen user permissions''') – разрешения, которыми обладает редактируемый пользователь (рис.3).&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF106_81_2.jpg|Рис. 3|300px]]Рис. 3. Настройка прав доступа.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Каждая строка содержит три части: приложение, модель и право доступа в человеко-понятной форме. Например, '''news | comment | Can add comment''' означает, что пользователь может добавлять комментарии в модель '''comment''' приложения '''news'''. Проверку прав доступа&lt;br /&gt;
нужно осуществлять на уровне представлений или/и шаблонов. На&lt;br /&gt;
уровне моделей она не производится, поэтому комментарии к нашим&lt;br /&gt;
новостям могут добавлять любые посетители, даже не имеющие прав&lt;br /&gt;
на совершение таких действий.&lt;br /&gt;
&lt;br /&gt;
Условно, всех пользователей системы можно разделить на две&lt;br /&gt;
группы: анонимные и авторизованные. Особый случай – это суперпользователь; в ''Django'', как и в Linux, он царь и бог и обладает&lt;br /&gt;
всеми возможными правами. Назначить себя суперпользователем&lt;br /&gt;
можно, установив галочку напротив поля '''Superuser status'''. Отметим&lt;br /&gt;
ещё два поля в разделе '''Permissions''':&lt;br /&gt;
* '''Staff status''' – если эта галочка установлена, пользователь может заходить в «админку» ''Django''.&lt;br /&gt;
* '''Active''' – если флажок снят, посетителю будет отказано в авторизации, даже когда он верно указывает свои имя и пароль.&lt;br /&gt;
&lt;br /&gt;
Создадим еще одно представление, с помощью которого будем удалять нежелательные комментарии:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot; &amp;gt;&lt;br /&gt;
@permission_required('news.delete_comment')&lt;br /&gt;
def delete_comment(request, news_id, comment_id):&lt;br /&gt;
comment = get_object_or_404(Comment,pk=comment_id)&lt;br /&gt;
comment.delete()&lt;br /&gt;
return HttpResponseRedirect(reverse('news.news_ detail',kwargs={'news_id':news_id}))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основным его отличием от виденных нами ранее является проверка прав доступа. Она реализована с помощью декоратора в строке 1 – кстати, не забудьте его импортировать.&lt;br /&gt;
&lt;br /&gt;
 from django.contrib.auth.decorators import permission_required&lt;br /&gt;
&lt;br /&gt;
Права доступа в декораторах определяются именем приложения&lt;br /&gt;
('''news''') и названием разрешения ('''delete_comment'''). Последнее получается автоматически конкатенацией действия ('''delete''') и модели.&lt;br /&gt;
Обратите внимание на строку 3: в ней мы извлекаем из базы данных единственный объект, но используем сокращение '''get_object_or_404()''', которое возвращает страницу 404 в случае отсутствия объекта. Не забудьте импортировать функцию '''get_object_or_404()''' в&lt;br /&gt;
ваше представление до её использования:&lt;br /&gt;
&lt;br /&gt;
 from django.shortcuts import get_object_or_404&lt;br /&gt;
&lt;br /&gt;
Теперь нам нужно связать URL с представлением:&lt;br /&gt;
&lt;br /&gt;
 url(r'^(?P&amp;lt;news_id&amp;gt;\d+)/(?P&amp;lt;comment_id&amp;gt;\d+)/delete/$','delete_comment',name='news.delete_comment'),&lt;br /&gt;
&lt;br /&gt;
Давайте расширим наш шаблон: во-первых, незачем показывать&lt;br /&gt;
форму анонимным пользователям, во-вторых, следует добавить&lt;br /&gt;
ссылку для удаления комментария, если посетитель обладает достаточными правами. Допишите следующий код после строки 10:&lt;br /&gt;
&lt;br /&gt;
    {% if perms.news.delete_comment %}&lt;br /&gt;
      &amp;lt;a href=”{% url news.delete_comment news_id=news.id,comment_id=comment.id %}”&amp;gt;[X]&amp;lt;/a&amp;gt;&lt;br /&gt;
    {% endif %}&lt;br /&gt;
&lt;br /&gt;
Это напоминает использование декораторов, за исключением&lt;br /&gt;
обращения к объекту '''perms'''. Теперь напротив каждого комментария&lt;br /&gt;
будет присутствовать ссылка для его удаления. Далее, заключите&lt;br /&gt;
форму (строки 21-25) в блок '''{% if %}''', чтобы она не отображалась&lt;br /&gt;
неавторизованным пользователям.&lt;br /&gt;
&lt;br /&gt;
 {% if user.is_authenticated %}&lt;br /&gt;
      ...&lt;br /&gt;
 {% endif %}&lt;br /&gt;
&lt;br /&gt;
Помимо '''perms''', содержащего права текущего пользователя, в&lt;br /&gt;
шаблон передается объект '''user''', предоставляющий доступ к прочим реквизитам: имени пользователя, хэшу пароля, данным о текущем состоянии (анонимный или авторизованный). Например, с помощью:&lt;br /&gt;
&lt;br /&gt;
 {% if user.is_superuser %}&lt;br /&gt;
&lt;br /&gt;
можно определить, является ли посетитель суперпользователем.&lt;br /&gt;
&lt;br /&gt;
===Вас взломали!===&lt;br /&gt;
&lt;br /&gt;
Казалось бы, все в порядке, но есть одна тонкость. Спрятав форму&lt;br /&gt;
от глаз неавторизованного пользователя, мы не лишили его возможности «заполнять» ее, генерируя HTTP-заголовки вручную – представление ведь осталось прежним! Чтобы закрыть лазейку, нужно перво-наперво импортировать исключение '''Http404''' (страница не найдена):&lt;br /&gt;
&lt;br /&gt;
 from django.http import Http404&lt;br /&gt;
&lt;br /&gt;
После проверки метода запроса в файле '''news/views.py''' (строка 3) добавьте конструкцию&lt;br /&gt;
&lt;br /&gt;
 if not request.user.is_authenticated(): raise Http404&lt;br /&gt;
&lt;br /&gt;
она выбрасывает исключение, если посетитель неавторизован.&lt;br /&gt;
&lt;br /&gt;
Помимо '''Http404''', можно создавать ответы с различными HTTP-кодами, например, '''HttpResponseForbidden''' (403 – доступ запрещен)&lt;br /&gt;
и так далее. Заметьте, что '''Http404''' – это именно исключение и его&lt;br /&gt;
нужно возбуждать с помощью '''raise''', тогда как остальные ответы&lt;br /&gt;
возвращаются посредством '''return'''.&lt;br /&gt;
&lt;br /&gt;
И, напоследок, выполним еще одну оптимизацию. Так как комментарии могут оставлять только авторизованные пользователи, не&lt;br /&gt;
будем утруждать их вводом своего имени. Система обработки форм&lt;br /&gt;
позволяет динамически заполнять некоторые поля исходными данными. При замене&lt;br /&gt;
&lt;br /&gt;
 form = CommentForm()&lt;br /&gt;
&lt;br /&gt;
на&lt;br /&gt;
&lt;br /&gt;
 form = CommentForm(initial={'username':request.user.username})&lt;br /&gt;
&lt;br /&gt;
поле '''username''' автоматически получит имя текущего авторизованного пользователя.''' LXF'''&lt;/div&gt;</summary>
		<author><name>Gordano</name></author>	</entry>

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

	</feed>