1. 程式人生 > >Django第七篇-----如何提交表單

Django第七篇-----如何提交表單

目錄

如何獲取url的資訊

其他可用來反爬的資訊

一個簡單的表單處理

簡單的驗證

第一個表單類

在檢視中使用表單物件

改變欄位的渲染方式

設定最大長度

設定初始值

自定義驗證規則

指定標註


如何獲取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')