[Перевод] Эффективный Django. Часть 2
Продолжение перевода статей о Django с сайта effectivedjango.com. Наткнулся я на этот сайт во время изучения данного фреймворка. Информация размещенная на этом ресурсе показалась мне полезной, но так как нигде не нашел перевода на русский, решил сделать сие доброе дело сам. Этот цикл статей, как мне думается, будет полезен веб-разработчикам, которые делают только первые шаги в изучении Django.Введение Эффективный Django. Руководство Тестирование в Django Понимание Middleware’ов Базы данных и модели Представления-классы (CBV) Формы 3.1. Основы представлений Представления Django получают HTTP запрос и возвращает пользователю HTTP ответ: Любой вызываемый объект языка Python может быть представлением. Единственное жесткое и необходимое требование заключается в том, что вызываемый объект Python должен принимать объект запроса в качестве первого аргумента (обычно этот параметр так и именуют — request). Это означает, что минимальное представление будет очень простым: from django.http import HttpResponse
def hello_world (request): return HttpResponse («Hello, World») Конечно, как и большинство других фреймворков, Django позволяет вам передавать аргументы в представление через URL. Мы поговорим об этом, когда будем строить наше приложение.3.2. Общие представления и представления-классы общие представления всегда предоставляют какой-нибудь базовый функционал: визуализировать шаблон, перенаправить, создать, отредактировать модель и т. д. начиная с версии 1.3, для общих представлений в Django появились представления-классы (CBV); общие представления и CBV предоставляют более высокий уровень абстракции и компонуемости; кроме того, они скрывают немало сложности, которая иначе могла бы сбить с толку новичков; к счастью, в новых версиях Django документация всего этого стала намного лучше. Django 1.3 вводит представления-классы на которых мы сосредоточимся в этой главе. Представления-классы или CBV, могут устранить много шаблонного кода из ваших представлений, особенно из представлений для редактирования чего-либо, где вы хотите предпринимать различные действия для GET и POST запросов. Представления-классы дадут вам возможность собирать функционал по частям. Недостаток заключается в том, что вся эта мощь влечет за собой некоторое дополнительное усложнение.3.3. Представления-классы (CBV) Минимальное представление, реализованное как CBV, является наследником класса View doc и реализует поддерживаемые HTTP-методы. Ниже находится очень небольшое представление «Hello, World» написанное нами ранее, но выполненное в виде представления-класса: from django.http import HttpResponse from django.views.generic import View
class MyView (View):
def get (self, request, *args, **kwargs): return HttpResponse («Hello, World») В представлении-классе имена методов HTTP отображаются на методы класса. В нашем случае мы определили обработчик для GET-запроса используя метод класса get. Точно так же, как при реализации функцией, этот метод принимает объект запроса в качестве первого параметра и возвращает HTTP ответ. Примечание: Допустимые сигнатурыВы можете заметить несколько дополнительных аргументов в сигнатуре функции, по сравнению с представлением написанным нами ранее, в частности *args и **kwargs. CBV впервые были создавались для того, что бы сделать «общие» представления Django более гибкими. Подразумевалось, что они будут использоваться в множестве различных контекстов, с потенциально различными аргументами, извлеченными из URL. Занимаясь последний год написанием представлений-классов, я продолжаю писать их используя допустимые сигнатуры, и каждый раз это оказывается полезным в неожиданных ситуациях.
3.4. Вывод перечня контактов Мы начнем с представления, которое выводит список контактов из базы данных.Базовая реализация представления очень коротка. Мы можем написать его всего-лишь в несколько строк. Для этого в файле views.py нашего приложения contacts наберем следующий код:
from django.views.generic import ListView
from contacts.models import Contact
class ListContactView (ListView):
model = Contact Класс ListView doc, от которого мы наследовали представление, сам составлен из нескольких примесей, которые реализуют некоторое поведение. Это дает нам большую мощь при малом количестве кода. В нашем случае мы указали модель (model = Contact), что заставит это представление вывести список всех контактов модели Contact из нашей базы данных.3.5. Определяем URL’ы Конфигурация URL (URLconf) указывает Django как по адресу запроса найти ваш Python-код. Django смотрит конфигурацию URL, которая определена в переменной urlpatterns файла urls.py.Давайте добавим в файл addressbook/urls.py URL-шаблон для нашего представления, которое отображает список контактов:
from django.conf.urls import patterns, include, url
import contacts.views
urlpatterns = patterns ('', url (r'^$', contacts.views.ListContactView.as_view (), name='contacts-list',), ) использование функции url () не является строго обязательным, но я предпочитаю использовать ее: когда вы начнете добавлять больше информации в URL-шаблоны, она позволит вам использовать именованные параметры, делая код более чистым; первый параметр принимаемый функцией url () — это регулярное выражение. Обратите внимание на замыкающий символ $; как думаете, почему он важен? вторым параметром указывается вызываемое представление. Это может быть как непосредственно вызываемый объект (импортированный вручную), так и строка описывающая его. Если это строка, то в случае соответствия URL-шаблона строке запроса, Django сам импортирует необходимый модуль (до последней точки), и вызовет последний сегмент строки (после последней точки); замете, что когда мы используем представление-класс, мы обязаны использовать реальный объект, а не строку описывающую этот объект. Мы должны так делать из за того, что мы вызываем метод класса as_view (). Этот метод возвращает обертку над нашим классом, которую может вызвать диспетчер URL Django; имя, данное URL-шаблону, позволят вам делать обратный поиск; имя URL полезно, когда вы ссылаетесь из одного представления на другое, или выполняете перенаправление, так как вы можете управлять структурой URL’ов из одного места. В то время, как переменная urlpatterns должна быть определена, Django также позволяет вам определить несколько других значений (переменных) для исключительных ситуаций. Эти значения включают в себя handler403, handler404, и handler500, которые указывают Django, какое представление использовать в случае ошибки HTTP. Для более подробной информации смотрите документацию Django по конфигурации URL. Примечание: Ошибки импортирования конфигурации URLDjango загружает конфигурацию URL очень рано во время старта и пытается импортировать найденные внутри модули. Если хотя бы одна из операций импорта обернется неудачей, сообщение об ошибке может быть немного непонятным. Если ваш проект перестал работать по причине ошибки импорта, попробуйте импортировать конфигурацию URL в интерактивной оболочке. Это позволяет, в большинстве случаев, определить в каком месте возникли проблемы.
3.6. Создание Шаблона Сейчас, определив URL для нашего представления списка контактов, мы можем испробовать его. Django включает в себя сервер подходящий для целей разработки, который вы можете использовать для тестирования вашего проекта: (venv: tutorial)$ python ./manage.py runserver 0.0.0.0:8080 Validating models…
0 errors found November 04, 2014 — 15:25:05 Django version 1.6.7, using settings 'addressbook.settings' Starting development server at http://0.0.0.0:8080/ Quit the server with CONTROL-C. Если вы посетите http://localhost:8080/ в вашем браузере, вы все же получите ошибку TemplateDoesNotExists Примечание переводчика: localhost указывайте в том случае, если запускаете браузер с того же хоста, где запущен сервер. Если сервер у вас запущен на другом хосте (как у меня) — вместо localhost укажите IP адрес этого хоста (в моем случае это 192.168.1.51).
Большинство общих представлений Django (сюда относиться, ListView использованный нами) имеет предустановленное имя шаблона, который они ожидают найти. Мы можем увидеть в этом сообщении об ошибке, что представление ожидало найти файл шаблона с именем contact_list.html, которое было получено из имени модели. Давайте создадим такой шаблон.По умолчанию, Django ищет шаблоны в приложениях, так же как и в директориях, указанных в settings.TEMPLATE_DIRS. Общие представления ожидают, что шаблоны найдутся в директории приложения (в данном случае в директории contacts), и имя файла будет содержать имя модели (в данном случае ожидаемое имя файла: contact_list.html). Это приходится кстати, когда вы разрабатываете приложения для повторного использования: пользователь вашего приложения может создать свои шаблоны, которые перекроют шаблоны по умолчанию, и они будут хранится в директории, прямо связанной с приложением.
Примечание переводчика: Django ожидает, что искомый шаблон находится по адресу имя_приложения/templates/имя_приложения/имя_шаблона
Для наших целей, однако, нам не нужен дополнительный слой из структур директорий, так что мы определим шаблон явно, использую свойство template_name нашего представления-класса. Давайте добавим одну строчку в views.py: from django.views.generic import ListView
from contacts.models import Contact
class ListContactView (ListView):
model = Contact template_name = 'contact_list.html' Создадим в директории contacts (это директория с приложением) поддиректорию templates, а в ней создадим файл шаблона contact_list.html:
Contacts
-
{% for contact in object_list %}
- {{ contact }} {% endfor %}
3.7. Создаем контакты Добавление информации в базу данных через интерактивную оболочку занимает слишком много времени, так что давайте создадим представление для добавления новых контактов.Так же как и в случае с выводом списка контактов, воспользуемся одним из общих представлений Django. В файле views.py мы добавим несколько строчек:
from django.core.urlresolvers import reverse from django.views.generic import ListView from django.views.generic import CreateView
from contacts.models import Contact
class ListContactView (ListView):
model = Contact template_name = 'contact_list.html'
class CreateContactView (CreateView):
model = Contact template_name = 'edit_contact.html'
def get_success_url (self): return reverse ('contacts-list') Примечание переводчика: Если вы используете Django версии >= 1.7, то можете добавить к классу CreateContactView дополнительное поле:
fields = ['first_name', 'last_name', 'email'] Это не обязательно, но с версии Django 1.7 неиспользование этого поля в классах с автоматическим генерированием форм объявлено устаревшим (при выполнении тестов вам об этом сообщат). Если вы его не укажете — то в форме редактирования будут использоваться все поля, но с версии Django 1.8 такое поведение будет удалено. Большинство общих представлений, которые работают с формами имеют концепцию «удачного URL»: такого URL, на которой перенаправляется пользователь, после того как форма была удачно обработана. Все представления обрабатывающие формы твердо придерживаются практики POST-перенаправление-GET для принятия изменений, так что обновление конечной страницы не отправляет заново форму. Вы можете реализовать это концепцию как свойство класса, либо переопределить метод get_success_url (), как это сделали мы. В нашем случае мы используем функцию reverse для вычисления URL’а списка контактов. Примечание: Контекстные переменные в представлениях-классахНабор переменных доступных в шаблоне, когда он выводится, называется Контекстом. Контекст — это комбинация данных из представления и информации из процессоров контекста.Когда вы используете встроенные общие представления, не совсем очевидно какие переменные доступны в контексте. Со временем вы откроете для себя, что их имена (предоставляемые общими представлениями в контекст шаблона) достаточно последовательны — form, object и object_list часто используются — хотя это не поможет вам в начале пути. К счастью, документация по этому вопросу очень похорошела с версии Django 1.5.В представлениях-классах метод get_context_data () используются для добавления информации в контекст. Если вы перегрузите этот метод, вам нужно будет разрешить **kwargs и вызвать суперкласс.
Шаблон добавления контакта будет немного более сложный, чем шаблон списка контактов, но не слишком. Наш шаблон contacts/templates/edit_contact.html будет выглядеть как то так:
Add Contact
back to list Несколько новых штук на заметку: form из контекста — это Django Form для нашей модели. Так как мы не указали ни одного своего, Django создал один для нас. Как заботливо; если бы мы просто написали {{ form }} мы бы получили табличные ряды;, но мы добавляем .as_ul, что заставляет выводить поля ввода как элементы ненумерованного списка. Попробуйте вместо этого использовать .as_p и посмотреть что из этого получится; когда мы выводим форму (пр.: автоматически сгенерированную) выводятся только наши поля, но не обрамляющий форму тег