Содержание
- Получение данных из объекта запроса
- Пример обработки простой формы
- Усовершенствование примера обработки простой формы
- Простая проверка данных
- Создание формы для контактной информации
- Ваш первый класс формы
- Используем формы в представлениях
- Изменения способа отображения полей
- Установка максимального размера поля
- Установка начальных значений
- Собственные правила проверки
- Определение меток
- Настройка дизайна формы
- Что дальше?
Перевод © Попов Руслан <ruslan.popov • gmail>
HTML формы являются основой интерактивных веб-сайтов, от простой
формы поиска Google и вездесущих форм для комментирования в блогах
до сложных уникальных интерфейсов для ввода данных. Эта глава
рассматривает возможности Django по обработке форм, проверки
переданных значений. Здесь мы рассмотрим объекты
HttpRequest
и Form
.
Мы впервые коснулись объектов HttpRequest
в главе «Представления и привязки URL» при начальном
изучении функций представления, но мы многого тогда не
рассказали. Помните, каждая функция представления принимала
объект HttpRequest
в качестве первого
аргумента, как в нашем представлении
hello()
:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world")
HttpRequest
объекты, в нашем случае
представленные переменной request
, обладают
рядом интересных атрибутов и методов, с которыми вам следует
познакомиться, чтобы вы знали их возможности. Вы можете
использовать данные атрибуты для получения информации о текущем
запросе (т.е., о пользователе и браузере, который запросил
текущую страницу вашего сайта) во время выполнения функции
представления.
HttpRequest
объекты содержат информацию
о запрошенном URL:
Таблица 7.1. Информация об URL
Атрибут/Метод | Описание | Пример |
---|---|---|
request.path | Полный путь, без домена, но с начальным слешом. | /hello/ |
request.get_host() | Имя компьютера (т.е., «домен»). | 127.0.0.1:8000 или www.example.com |
request.get_full_path() | Равен path, но со строкой запроса (если она существует). | /hello/?print=true |
request.is_secure() | True в случае использования HTTPS. Иначе False. | True или False |
Всегда используйте эти атрибуты/методы вместо прямого вписывания URL в ваши представления. Такой подход делает код более гибким и его можно будет повторно использовать в других местах. Простейший пример:
# BAD!
def current_url_view_bad(request):
return HttpResponse("Welcome to the page at /current/")
# GOOD
def current_url_view_good(request):
return HttpResponse("Welcome to the page at %s" % request.path)
Атрибут request.META является словарём, который содержит все доступные HTTP заголовки текущего запроса, включая IP адрес посетителя и информацию об его браузере (название и версию). Следует отметить, что полный список доступных заголовков зависит от того, какие заголовки были посланы браузером посетителя и какие заголовки были установлены веб-сервером. Перечислим несколько стандартных ключей этого словаря:
HTTP_REFERER — ссылка на страницу с которой пришли на текущую, если такая существует.
HTTP_USER_AGENT — идентификационная строка браузера. Обычно выглядит так: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17".
REMOTE_ADDR — IP адрес пользователя, т.е., "12.245.67.89". (Если запрос был передан через прокси, тогда адрес может быть передан в виде списка: "12.245.67.89,23.45.78.90".)
Следует отметить, что так как request.META
является обычным словарём языка Python, вы получите исключение
KeyError
, если попытаетесь использовать
несуществующий ключ. (Так как HTTP заголовки являются
внешними данными — они передаются браузерами посетителей — им не стоит доверять, и вы
должны всегда проектировать ваше приложение на грамотную
обработку возникающих ошибок, если нужного заголовка нет или
он пустой.) Следует использовать блок
try/except или метод get()
для обработки случая с неопределёнными ключами:
# BAD!
def ua_display_bad(request):
ua = request.META['HTTP_USER_AGENT'] # Might raise KeyError!
return HttpResponse("Your browser is %s" % ua)
# GOOD (VERSION 1)
def ua_display_good1(request):
try:
ua = request.META['HTTP_USER_AGENT']
except KeyError:
ua = 'unknown'
return HttpResponse("Your browser is %s" % ua)
# GOOD (VERSION 2)
def ua_display_good2(request):
ua = request.META.get('HTTP_USER_AGENT', 'unknown')
return HttpResponse("Your browser is %s" % ua)
Мы рекомендуем вам написать небольшое представление, которое будет отображать все данные из request.META, так вы сможете узнать что там есть. Вот так может выглядеть ваше представление:
def display_meta(request):
values = request.META.items()
values.sort()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return HttpResponse('<table>%s</table>' % '\n'.join(html))
В качестве упражнения, вы можете преобразовать данный код для использования возможностей шаблонной системы Django, а не использовать «сырой» HTML.
Кроме основных метаданных о запросе,
HttpRequest
имеет два атрибута, которые
содержат информацию переданную пользователем:
request.GET и request.POST. Оба
этих атрибута являются словарными объектами, которые
предоставляют доступ к данным GET и
POST.
Словарные объекты
Когда мы говорим, что request.GET и
request.POST являются
«словарными» объектами, мы подразумеваем, что
они ведут себя как обычные словари языка Python, но
технически не являются словарями. Например,
request.GET и request.POST
обладают методами get()
,
keys()
и
values()
и вы можете выполнять
итерацию по их ключам, так for key in request.GET.
Так в чём разница? В том, что эти объекты обладают дополнительными методами, которых нет у обычных словарей. Мы ещё остановимся на этом.
Вы можете встретиться с подобным термином —
«файловые объекты» — такие объекты
обладают несколькими основными методами, подобными
read()
, которые позволяют работать с
ними почти как с настоящими файлами.
POST данные обычно получают из HTML <form>, а GET данные могут приходить как от форм, так и из URL.
16 комментариев | Оставьте комментарий
У меня что-то не вышло с display_meta, ругается на UnicodeDecodeError
В Meta передаётся информация на языке, который сложнее 7 бит ;)
Может нужно было не str, а unicode использовать при формировании html.
Мне помогла такая конструкция:
html.append(('<tr><td>%s</td><td>%s</td></tr>' % (k, v)).decode('cp1251'))
В XXI веке правильнее будет везде использовать UTF-8.
Блин, не то скопировал
return render_to_response('display_meta.html', {'html' : html})
конецчно же
Ответ на gamak
Блин, не то скопировал
return render_to_response('display_meta.html', {'html' : html})
конецчно же
Для вопросов есть форум: /forum/
пытаюсь вынести html разметку в шаблон вот уже вторую неделю, на форуме информации по этому вопросу ноль. Может направите в какую сторону размышлять. Сейчас представление выглядит так
def display_meta(request):
values = request.META.items()
values.sort()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return render_to_response('chablon.html',{'meta': '\n'.join(html))
chablon.html выглядит так
...
...
<table>{{meta}}</table>
...
...
все символы html разметки заменяются, почему то заменяются подстановками
<table> <tr> <td>
и вообще как всю разметку из представления вынести, подскажите пожалуйста!!! Заранее спасибо!
Ответ на kinev
пытаюсь вынести html разметку в шаблон вот уже вторую неделю, на форуме информации по этому вопросу ноль. Может направите в какую сторону размышлять. Сейчас представление выглядит так
def display_meta(request):
values = request.META.items()
values.sort()
html = []
for k, v in values:
html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
return render_to_response('chablon.html',{'meta': '\n'.join(html))
chablon.html выглядит так
...
...
<table>{{meta}}</table>
...
...
все символы html разметки заменяются, почему то заменяются подстановками
<table> <tr> <td>
и вообще как всю разметку из представления вынести, подскажите пожалуйста!!! Заранее спасибо!
А вы создавали тему на форуме с вопросом? /forum/topic/205/ в этой теме есть линки на примеры шаблонов. А вообще фильтр safe вам в помощь.
Ответ на alerion
А вы создавали тему на форуме с вопросом? /forum/topic/205/ в этой теме есть линки на примеры шаблонов. А вообще фильтр safe вам в помощь.
Спасибо за ссылки и информацию к размышлению. Тему не открывал, думаю не такая уж большая у меня проблема что бы ради неё плодить темы на форумах. Пока что придумал вот такой ход.
def display_meta(request):
values = request.META.items()
values.sort()
html = []
for k, v in values:
html.append((k, v))
return render_to_response('chablon.html',{'key': html[i] [0], 'vol': html[i] [1] )
теперь думаю как значение переменной i перебрать.
За помощь спасибо!
Ответ на kinev
Спасибо за ссылки и информацию к размышлению. Тему не открывал, думаю не такая уж большая у меня проблема что бы ради неё плодить темы на форумах. Пока что придумал вот такой ход.
def display_meta(request):
values = request.META.items()
values.sort()
html = []
for k, v in values:
html.append((k, v))
return render_to_response('chablon.html',{'key': html[i] [0], 'vol': html[i] [1] )
теперь думаю как значение переменной i перебрать.
За помощь спасибо!
Ну что же вы делаете? Вы же решили изучить Джанго, значит надо руководствоваться идеологией фреймворка и советами авторов книги(как собственно авторов самого фреймворка). Ваше представление, не спорю, наверняка работает, но ведь это не "торт". Вот как на мой взгляд должно выглядеть представление:
def display_meta(request):
val_meta = request.META.items()
val_meta.sort()
return render_to_response('http_meta/list_meta.html', {'list_meta': val_meta})
В свою очередь у вас должен быть дочерний шаблон list_meta.html(названия могут быть, какие ваша душа пожелает, и это относиться ко всем рукотворным элементам), со следующим содержанием:
{% extends "base.html" %}
{% block title %}The list of Request_META{% endblock %}
{% block content %}
<table>
{% for k, v in list_meta %}
<tr><td>{{ k }}</td><td>{{ v }}</td></tr>
{% endfor %}
</table>
{% endblock %}
Как видно дочерний шаблон обращается к основному шаблону base.html. Код этого шаблона:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My exsample site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>
Я, конечно, не претендую на истину в последней инстанции, но считаю, что так будет гораздо "православней" и более идеологически верно:)
Ответ на aliksanderz
Ну что же вы делаете? Вы же решили изучить Джанго, значит надо руководствоваться идеологией фреймворка и советами авторов книги(как собственно авторов самого фреймворка). Ваше представление, не спорю, наверняка работает, но ведь это не "торт". Вот как на мой взгляд должно выглядеть представление:
def display_meta(request):
val_meta = request.META.items()
val_meta.sort()
return render_to_response('http_meta/list_meta.html', {'list_meta': val_meta})
В свою очередь у вас должен быть дочерний шаблон list_meta.html(названия могут быть, какие ваша душа пожелает, и это относиться ко всем рукотворным элементам), со следующим содержанием:
{% extends "base.html" %}
{% block title %}The list of Request_META{% endblock %}
{% block content %}
<table>
{% for k, v in list_meta %}
<tr><td>{{ k }}</td><td>{{ v }}</td></tr>
{% endfor %}
</table>
{% endblock %}
Спасибо большое за помощь, точно к такому же решению пришел, прочитав еще 3 главы далее. Увидел похожую схему в разборе одного из шаблона, только там вместо табличных тегов стояли <ul></ul>. Сразу же понял что ковырять надо не представления а шаблон.
Ответ на aliksanderz
Ну что же вы делаете? Вы же решили изучить Джанго, значит надо руководствоваться идеологией фреймворка и советами авторов книги(как собственно авторов самого фреймворка). Ваше представление, не спорю, наверняка работает, но ведь это не "торт". Вот как на мой взгляд должно выглядеть представление:
def display_meta(request):
val_meta = request.META.items()
val_meta.sort()
return render_to_response('http_meta/list_meta.html', {'list_meta': val_meta})
В свою очередь у вас должен быть дочерний шаблон list_meta.html(названия могут быть, какие ваша душа пожелает, и это относиться ко всем рукотворным элементам), со следующим содержанием:
{% extends "base.html" %}
{% block title %}The list of Request_META{% endblock %}
{% block content %}
<table>
{% for k, v in list_meta %}
<tr><td>{{ k }}</td><td>{{ v }}</td></tr>
{% endfor %}
</table>
{% endblock %}
Добрый день.
Мне кажется
def display_meta(request):
val_meta = request.META.items()
val_meta.sort()
return render_to_response('http_meta/list_meta.html', {'list_meta': val_meta})
не будет работать
нужно еще строку добавить, что-то типа
dict_meta = dict(val_meta)
и сослаться на этот получившийся словарь
return render_to_response('http_meta/list_meta.html', {'list_meta': dict_meta})
Ответ на Aleksey
Добрый день.
Мне кажется
def display_meta(request):
val_meta = request.META.items()
val_meta.sort()
return render_to_response('http_meta/list_meta.html', {'list_meta': val_meta})
не будет работать
нужно еще строку добавить, что-то типа
dict_meta = dict(val_meta)
и сослаться на этот получившийся словарь
return render_to_response('http_meta/list_meta.html', {'list_meta': dict_meta})
Все там правильно.
Ответ на RaD
В XXI веке правильнее будет везде использовать UTF-8.
+100500