Главная | Архив новостей | Общение | Площадка | Примеры OpenID
Хостинг Django от «Джино»
Оглавление

Ваше третье представление: Динамические URL

В нашем представлении current_datetime содержимое страницы — текущая дата и время — были динамическими, но URL оставался статическим. В большинстве динамических web-приложений URL содержат параметры, которые влияют на генерацию страницы. Например, онлайн магазин может отображать книгу по её собственному URL, таким как /books/243/ и /books/81196/.

Давайте создадим третье представление, которое отображает текущую дату и время со смещением на указанное количество часов. Цель — реализовать функциональность, с помощью которой сайт будет по URL /time/plus/1/ отдавать текущее время сдвинутое на час вперёд, а по URL /time/plus/2/ — на два часа вперёд и так далее.

Новичок может подумать, что потребуется создавать функцию представления для каждого смещения часа, что может выразится в следующей схеме URL:

urlpatterns = patterns('',
    ('^time/$', current_datetime),
    ('^time/plus/1/$', one_hour_ahead),
    ('^time/plus/2/$', two_hours_ahead),
    ('^time/plus/3/$', three_hours_ahead),
    ('^time/plus/4/$', four_hours_ahead),
)

Очевидно, это направление мысли является ущербным. Такой подход не только приведёт к избыточности функций представления, но и к тому, что приложение будет явно ограничено заранее заданным диапазоном смещений — один, два, три или четыре часа. Если мы решим создать страницу, которая отображает текущее время со смещением на пять часов вперёд, нам потребуется создать отдельное представление и внести дополнительную строчку в схему URL, продолжая создавать избыточность. Нам потребуется немного окунуться в теорию.

Слово о красивых URL

Если вы работали с другими платформами разработки web-приложения, такими как PHP или Java, вы можете подумать: «Эй, давайте использовать параметр строки запроса!» — что-нибудь аналогичное /time/plus?hours=3, в котором смещение будет указано через параметр hours в URL.

Вы можете сделать так и с Django (и мы расскажем об этом в главе 7 FIXME), но Django пропагандирует философию использования красивых URL. URL /time/plus/3/ гораздо яснее, проще, более читаемое, его проще сказать кому-нибудь вслух и ... просто проще, чем его оппонент. Красивый URL являются характеристикой качества web-приложения.

Система схемы URL Django поощряет создание красивых URL, упрощая использование таких URL, в отличие от других.

Как же мы должны спроектировать наше приложение для обработки соответствующих смещений времени? Ответ лежит в использовании шаблонов подстановки. Как мы упоминали ранее, шаблон URL является регулярным выражением. Следовательно, мы можем использовать шаблон \d+ для выделения одной или более цифр:

urlpatterns = patterns('',
    # ...
    (r'^time/plus/\d+/$', hours_ahead),
    # ...
)

(Мы используем #..., чтобы показать, что здесь могут быть другие шаблоны, которые мы временно исключили из данного примера.)

Новый шаблон схемы URL будет соответствовать любому URL, подобному /time/plus/2/, /time/plus/25/ и даже /time/plus/100000000000/. Давайте ограничим смещение 99-ю часами. Это означает, что мы разрешаем только одно- или двухзначиные числа. На языке регулярных выражений это преобразовывается в \d{1,2}:

(r'^time/plus/\d{1,2}/$', hours_ahead),

Замечание

При разработке web-приложения, важно всегда рассматривать наиболее диковинные варианты ввода данных и решать должно или нет приложение обрабатывать такой ввод. Мы ограничили здесь возможности ввода смещения 99-ю часами.

Ещё одной важной деталью, которую мы ввели здесь, является символ r в начале строки регулярного выражения. Он указывает Python, что строка является «сырой» — в её содержимом не следует интерпретировать обратные слеши. В обычной строке Python, обратные слеши используются для экранирования особых символов, например, \n — односимвольная строка. Если предварить её символом r, сделав её «сырой», Python не будет выполнять экранирование — таким образом, r'\n' станет двухсимвольной строкой, содержащей обратный слеш и символ n. Существует естественная коллизия между обычными обратными слешами и используемыми в регулярных выражениях. Крайне рекомендуется всегда использовать сырые строки при определении регулярных выражений в Python. С этого момента следует считать, что все шаблоны URL, показанные в этой книге, будут представлены сырыми строками.

После применения символов подстановки в URL необходим способ передачи выделенных подстановкой данных в функцию представления, это позволит нам использовать единственную функцию представления для любого разрешённого смешения часов. Мы осуществляем это с помощью установки скобок вокруг интересующей нас части шаблона URL. В рамках нашего примера, это будет любое число в URL, таким образом, надо расположить скобки вокруг выражения \d{1,2}, например:

(r'^time/plus/(\d{1,2})/$', hours_ahead),

Если у вас уже есть опыт работы с регулярными выражениями, то вам будет легко. Мы используем скобки для выделения данных из совпавшего текста.

В итоге схема URL будет выглядеть так:

from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = patterns('',
    (r'^hello/$', hello),
    (r'^time/$', current_datetime),
    (r'^time/plus/(\d{1,2})/$', hours_ahead),
)

Теперь напишем представление hours_ahead.

Порядок разработки

В данном примере мы сначала создали шаблон URL, а затем представление. Но в предыдущих примерах, мы сначала создавали представление, а затем — шаблон URL. Какой подход лучше?

Хорошо, каждый разработчик уникален.

Если вам комфортно видеть весь проект целиком, может быть вам будет проще создать схему URL для всего функционала сайта за один раз, в начале проекта, а затем реализовать каждую функцию представления. Такой подход имеет преимущество, так как предостявляет ясный список работа и, по сути, определяет требования к параметрам функций представления, которые вам потребуется реализовать.

Если вам комфортно разрабатывать проект, начиная с небольших компонентов, может быть вы предпочтёте сначала реализовать представления, а затем ассоциировать их с URL. Такой подход тоже имеет право на жизнь.

В конце концов, не важно какой из подходов лучше или хуже. Они оба правильные.

Представление hours_ahead очень похоже на представление current_datetime, которое мы написали ранее, с одним только отличием: оно принимает дополнительный аргумент — количество часов смещения. Вот его код:

from django.http import Http404, HttpResponse
import datetime

def hours_ahead(request, offset):
    try:
        offset = int(offset)
    except ValueError:
        raise Http404()
    dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
    html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
    return HttpResponse(html)

Рассмотрим каждую строчку этого кода:

  • Функция представления, hours_ahead, принимает два параметра: request и offset.

    • Параметр request является объектом HttpRequest, аналогичным используемому в представлениях hello и current_datetime. Мы повторим ещё раз: каждое представление всегда принимает объект HttpRequest в качестве первого аргумента.

    • Параметр offset является строкой, выделенной скобками в шаблоне URL. Например, если запрошенный URL был /time/plus/3/, тогда offset будет содержать строку '3'. Если /time/plus/21/ — строка '21'. Следует отметить, что выделенные значения всегда будут строками, не целыми, даже если строка составлены только из цифр.

      (Технически, захваченные значения всегда будут объектами Unicode, а не простыми строками Python, но пока об этом беспокоиться не следует.)

      Мы решили назвать данный параметр offset, но вы можете дать ему любое другое имя, главное, чтобы оно соответствовало требованиям языка Python для идентификаторов. Имя переменной само по себе ничего не означает. Имеет значение только то, что переменная является вторым аргументом функции, после request. (Также можно использовать ключевые параметры в схеме URL вместо позиционных. Мы расскажем об этом в главе 8 FIXME.)

  • Первое, что мы делаем в функции — вызываем int() для offset. Данная функция преобразовывает строковое значение в целое.

    Следует отметить, что Python вызовет исключение ValueError, если в процессе вызова int() данная функция не сможет осуществить конвертацию, например, для строки 'foo'. В данном примере, если мы получим ValueError, мы вызовем исключение django.http.Http404, которое, как вы можете представить, возвратит страницу с ошибкой 404 — «Страница не найдена»

    Проницательному читателю будет интересно: как мы сможем попасть в ветку с ValueError, учитывая то, что регулярное выражение в нашем шаблоне — (\d{1,2}) — принимает только цифры и, следовательно, offset всегда будет состоять из строки цифр? Ответ заключается в том, что мы и не рассчитываем на это, так как шаблон URL предоставляет простой, но достаточный уровень проверки, но мы попрежнему проверяем значение на случай, если данная функция представления будет вызвана каким-либо другим способом. Это хороший подход — реализация функций представления так, как-будто им в параметрах может передаваться всё что угодно. Помните про свободное связывание?

  • На следующей строке функции мы вычисляем текущую дату и время, а затем добавляем соответствующее число к часам. Мы уже встречались с datetime.datetime.now() в представлении current_datetime. Разница лишь в том, что здесь мы выполняем арифметические операции, создав объект datetime.timedelta и прибавив его к объекту datetime.datetime. Результат операции сохраняется в переменной dt.

    Данная строка также показывает почему мы вызываем int() для offset — функция datetime.timedelta требует, чтобы параметр hours содержал целое число.

  • Затем мы создаём HTML документ для данного представления, аналогично тому, как это делалось в представлении current_datetime. Есть небольшое отличие в этой строке, от предыдущей — здесь используется строка форматирования с двумя подстановками, а не одной. Следовательно, строка содержит две подстановки %s и кортеж, содержащий значения: (offset, dt)..

  • Наконец, мы возвращает HttpResponse. Вот и всё.

Реализовав данную функцию представления и привязав её к URL, запустите тестовый сервер Django (если он ещё не запущен) и посетите http://127.0.0.1:8000/time/plus/3/ для проверки работы функции. Затем попробуйте http://127.0.0.1:8000/time/plus/5/. Затем http://127.0.0.1:8000/time/plus/24/. Наконец, посетите http://127.0.0.1:8000/time/plus/100/, чтобы проверить, что шаблон URL принимает только одно- или двухсимвольные числа. Django должна отобразить «Страница не найдена» в этом случае. http://127.0.0.1:8000/time/plus/ (без указания часов) также должен вызвать ошибку 404.


Увидели ошибку?
Выделите её мышкой и нажмите
Ctrl-Enter
Обработано:
511 49 130 71

Версия книги
1.0 2.0
Версия 2.0 в процессе перевода!

Мой луч
Многообразие света

Полезное
Актуальные вакансии, Python работа для python-разработчиков.


Скачать в формате
CHM от 2 сентября

Заказать PDF файл можно через почту, чат, джаббер. Всего 2WMZ. Содержимое точно соответствует содержимому сайта.
Чем чаще заказываете — тем больше перевожу.

Русская группа

на поддержку перевода
Яндекс Яндекс.Деньги Хочу такую же кнопку
Ускорить процесс перевода!
R130494980980
Z425285133788
E112528079659
U327380922061

Книга помогла реализовать:
Проект «Мой луч»
АРМ УФМС.


Мой вебсайт стоит666 337,31 руб

© 2008-2009 Ruslan Popov @ gmail.com Powered by Django 1.1 beta 1 SVN-11114
Главная | Архив новостей | Общение | Площадка | Примеры OpenID