Django第七篇-----如何提交表單
目錄
如何獲取url的資訊
HttpRequest 物件中有一些關於當前所請求 URL 的資訊
其他可用來反爬的資訊
request.META 的值是一個 Python 字典,包含請求的所有 HTTP 首部,例如使用者的 IP 地址和使用者代理(useragent,通常是 Web 瀏覽器的名稱和版本)。注意,具體包含哪些首部取決於使用者傳送了什麼首部,以及Web 伺服器返回了什麼首部。這個字典中常見的幾個鍵有:
• HTTP_REFERER :入站前的 URL(可能沒有)。(注意,要使用錯誤的拼寫,即 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.345.67.89" 。(如果請求經由代理,這個首部的值可能是一組 IP 地址,以逗號分隔,例如 "12.345.67.89,23.456.78.90" 。)
注意,因為 request.META 是個普通的 Python 字典,所以嘗試訪問不存在的鍵時,丟擲 KeyError 異常。
# 不好 def ua_display_bad(request): ua = request.META['HTTP_USER_AGENT'] # 可能丟擲 KeyError return HttpResponse("Your browser is %s" % ua) # 好(版本 1) def ua_display_good1(request): try: ua = request.META['HTTP_USER_AGENT'] except KeyError: ua = 'unknown' return HttpResponse("Your browser is %s" % ua) # 好(版本 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))
view
{% extends "base.html" %}
{% block title %}My helpful display meta{% endblock %}
{% block h1 %}The display meta{% endblock %}
{% block item %}
<ul>
{% for item in item_list %}
<li>{{ item }}</li>{% endfor %}
</ul>
{% endblock %}
結果如下
一個簡單的表單處理
如下配置
urls.py
url(r'^search-form/$', search_form),
url(r'^search/$', search),
views.py
def search_form(request):
return render(request, 'search_form.html')
def search(request):
if 'q' in request.GET:
q = request.GET['q']
books = Book.objects.filter(title__icontains=q)
return render(request, 'search_results.html',
{'books': books, 'query': q})
else:
message = 'You submitted an empty form.'
return HttpResponse(message)
search_form.html
<html>
<head>
<title>Search</title>
</head>
<body>
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
search_results.html
<html>
<head>
<title>Book Search</title>
</head>
<body>
<p>You searched for: <strong>{{ query }}</strong></p>
{% if books %}
<p>Found {{ books|length }} book{{ books|pluralize }}.</p>
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
{% else %}
<p>No books matched your search criteria.</p>
{% endif %}
</body>
</html>
簡單的驗證
def search(request):
error = []
if 'q' in request.GET:
q = request.GET['q']
if not q:
error.append('請填寫內容')
elif len(q) > 20 or len(q) == 0:
error.append('字串超過20')
else:
books = Book.objects.filter(title__icontains=q)
return render(request, 'search_results.html',{'books': books, 'query': q})
return render(request, 'search_form.html',{'error': error})
<html>
<head>
<title>Search</title>
</head>
<body>
{% if error %}
{% for error_ in error %}
<li>{{ error_ }}</li>
{% endfor %}
{% endif %}
<form action="/search/" method="get">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
</body>
</html>
第一個表單類
Django 自帶了一個表單庫, django.forms ,它能處理本章所述的多數問題,從顯示 HTML 表單到驗證,都能勝任。下面我們使用這個 Django 表單框架為應用程式構建一個聯絡表單。
在 views.py 檔案所在的目錄( mysite )中建立 forms.py檔案,然後輸入下述內容:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField()
列印檢視
>>> from mysite.forms import ContactForm
>>> f = ContactForm()
>>> print(f.as_p())
>>> <p><label for="id_subject">Subject:</label> <input type="text" name="subject" required id=
"id_subject" /></p>
<p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /><
/p>
<p><label for="id_message">Message:</label> <input type="text" name="message" required id=
"id_message" /></p>
>>> print(f['subject'])
<input id="id_subject" name="subject" type="text" />
>>> print f['message']
<input id="id_message" name="message" type="text" />
在檢視中使用表單物件
views.py
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
......
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render(request, 'contact_form.html', {'form': form})
contact_form.html
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</form>
</body>
</html>
urls.py
# ...
from mysite.views import hello, current_datetime, hours_ahead, contact
urlpatterns = [
# ...
url(r'^contact/$', contact),
]
這個表單使用 POST 處理(要修改資料),因此要關心跨站請求偽造(Cross Site Request Forgery,CSRF)。
幸好,我們無需太過擔心,因為 Django 提供了非常易用的防護系統。簡單來說,所有通過 POST 指向內部
URL 的表單都應該使用 {% csrf_token %} 模板標籤。
改變欄位的渲染方式
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField()
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
設定最大長度
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=10)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
超過10長度就會無法輸入
設定初始值
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email', '[email protected]'), ['[email protected]'],)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm(
initial={'subject': 'max 10'}
)
return render(request, 'contact_form.html', {'form': form})
自定義驗證規則
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=10)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Django 的表單系統會自動查詢名稱以 clean_ 開頭、以欄位名結尾的方法。如果存在這樣的方法,在驗證過程中呼叫。這裡, clean_message() 方法會在指定欄位的預設驗證邏輯(這個 CharField 是必填的)執行完畢後呼叫。
指定標註
email = forms.EmailField(required=False, label='Your e-mail address')