Django表單

  提及django表單,那麼就須要深刻理解request這個對象。下面是參考djangobook網站內容,加上本身學習理解後實踐的一些經驗分享。 版本:django2.2.2 + python3.6 。css

 1. 關於requesthtml

  request.META 是一個Python字典,包含了全部本次HTTP請求的Header信息,好比用戶IP地址和用戶Agent(一般是瀏覽器的名稱和版本號)。 手動寫一個顯示request.META信息的頁面,這樣能夠直觀的看到裏面包含的元素信息, 以下:前端

views.py:python

def display_meta(request):
    values = request.META.items()
    values = sorted(values, key=lambda x: x[0])
    return render_to_response('display_meta.html', {'meta': values})
View Code

urls.py:數據庫

urlpatterns = [
    path('admin/', admin.site.urls),
    path('meta/', views.display_meta),
]
View Code

templates/display_meta.html :django

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>request meta</title>
</head>
<body>
<table border="1">
    <tr>
        <th>request</th>
        <th>info</th>
    </tr>
    {% for k, v in meta %}
        <tr>
            <td>{{ k }}</td>
            <td>{{ v }}</td>
        </tr>
    {% endfor %}
</table>
</body>
</html>
View Code

 2. 一個簡單的表單示例瀏覽器

  一般,表單開發分爲兩個部分: 前端HTML頁面用戶接口和後臺view函數對所提交數據的處理過程。下面演示一個經過搜索表單來驗證先後臺數據交互處理的示例。app

(1)如今咱們來創建個view來顯示一個搜索表單:books/views.py框架

from django.shortcuts import render_to_response
from books.models import Book
# Create your views here.


def search(request):
    errors = []
    if 'q' in request.GET:
        q = request.GET['q']
        if not q:
            errors.append('Enter a search term.')
        elif len(q) > 20:
            errors.append('Please enter at most 20 characters.')
        else:
            books = Book.objects.filter(title__icontains=q)
            return render_to_response('search_results.html', {'books': books, 'query': q})
    return render_to_response('search_form.html', {'errors': errors})
View Code

  這裏對錶單提交的數據進行了容錯處理,對於輸入錯誤或者不符合條件的給予必定提示。對於提交後的數據經過 title__icontains=q 進行數據庫過濾匹配,匹配到返回數據。ide

(2)前端頁面

  templates/search_form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Search</title>
</head>
<body>
    {% if errors %}
        <ul>
            {% for error in errors %}
            <li style="color: red;">{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    <form action="" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>
View Code

  templates/search_results.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>results</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>
View Code

  這裏{{ books|length }}和{{ books|pluralize }}是django模板語言特有功能,前面表示計算書的數量,後面是以複數表示出來。

(3)url路徑配置

from django.contrib import admin
from django.urls import path
from books import views as bk

urlpatterns = [
    path('admin/', admin.site.urls),
    path('search/', bk.search),
]
View Code

 3. 較爲複雜的表單示例

  上面表單只包含一個字段 q , 這簡單的例子,咱們不須要使用Django表單庫來處理,可是複雜一點的表單就須要多方面的處理。咱們如今來一下一個較爲複雜的例子:站點聯繫表單,這個表單包括用戶提交的反饋信息,一個可選的e-mail回信地址,當這個表單提交而且數據經過驗證後,系統將自動發送一封包含題用戶提交的信息的e-mail給站點工做人員。

(1)先從前端頁面入手,templates/contact_form.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Contanct us</title>
</head>
<body>
    <h1>Contact us</h1>
    {% if errors %}
        <ul>
            {% for error in errors %}
            <li style="color: red;">{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}

    <form action="/contact/" method="post">
        {% csrf_token %}
        <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
        <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p>
        <p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p>
        <input type="submit" value="Submit">
    </form>
</body>
</html>
View Code

  定義了三個字段:主題、e-mail和反饋信息。除了e-mail字段可選,其餘兩個字段都是必填項。

(2)再來看看視圖的代碼,contact/views.py

#!/usr/bin/python
# _*_coding:utf-8_*_
# @Time     : 2019/7/4 上午10:47
# @Author   : blackysy
# @File     : views.py.py
# @Software : PyCharm

from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response


def contact(request):
    errors = []
    if request.method == 'POST':
        if not request.POST.get('subject', ''):
            errors.append('Enter a subject')
        if not request.POST.get('message', ''):
            errors.append('Enter a message.')
        if request.POST.get('email') and '@' not in request.POST['email']:
            errors.append('Enter a valid e-mail address.')
        if not errors:
            send_mail(
                request.POST['subject'],
                request.POST['message'],
                request.POST.get('email', 'norepl@example.com'),
                ['blackysy@qq.com'],
            )
            return HttpResponseRedirect('/contact/thanks/')
    return render_to_response('contact_form.html', {'errors': errors,
                                                    'subject': request.POST.get('subject', ''),
                                                    'message': request.POST.get('message', ''),
                                                    'email': request.POST.get('email', ''),
                                                    })
View Code

  默認GET請求時,會直接返回一個表單頁面給用戶,只有POST纔會進一步處理,由於有必填項,這裏作了些驗證。最後調用send_mail方法發送郵件,發送郵件還須要配置settings.py文件,配置參考以下:

EMAIL_HOST = 'mail.example.com.cn'
EMAIL_PORT = 25
EMAIL_HOST_USER = 'blackysy'
EMAIL_HOST_PASSWORD = 'blackysy'
View Code

(3)最後是url.py

from django.contrib import admin
from django.urls import path
from spider import views
from books import views as bk
from contact import views as ct

urlpatterns = [
    path('admin/', admin.site.urls),
    path('search/', bk.search),
    path('contact/', ct.contact),
]
View Code

 4. 第一個Form類

  表單框架最主要的用法是,爲每個將要處理的HTML的 <form> 定義一個Form類。 在這個例子中,咱們只有一個 <form>,所以咱們只需定義一個Form類。 這個類能夠存在於任何地方,甚至直接寫在 views.py 文件裏也行,可是社區的慣例是把Form類都放到一個文件中:forms.py, 在存放 views.py 的目錄中,建立這個文件。這裏建立在contact/forms.py,代碼以下:

from django import forms


class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False, label='E-mail')
    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
View Code

  表單中每個字段做爲Form類的屬性,被展示爲Field類,這裏只使用到CharField和EmailField類。除了email其餘的默認是必填項,經過required=False實現非必填。這裏還加入了自定義規則校驗的方法 clean_message ,校驗提交字數若是小於4個就返回一個錯誤提示。Form表單自定義校驗方法前面必須是 'clean_',後面是具體的字段名稱,必須和上面定義的相同。

  另外默認輸出的是table格式,還能夠經過as_ul()、as_p()輸出這兩種格式。標籤<table>、<ul>、<form>的開閉合標記沒有包含於輸出當中,這樣你就能夠添加額外的行或者自定義格式。代碼示例以下:

In [1]: from contact.forms import ContactForm                                                                                                                                                
In [2]: f = ContactForm() 
In [3]: print(f)                                                                                                                                                                             
<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" required id="id_subject"></td></tr>
<tr><th><label for="id_email">Email:</label></th><td><input type="email" name="email" id="id_email"></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" required id="id_message"></td></tr>
In [4]: print(f.as_ul())                                                                                                                                                                     
<li><label for="id_subject">Subject:</label> <input type="text" name="subject" required id="id_subject"></li>
<li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email"></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" required id="id_message"></li>
In [5]: 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>
View Code

  也能夠單個字段獲取,代碼:

In [6]: print(f['subject'])                                                                                                                                                                  
<input type="text" name="subject" required id="id_subject">
In [7]: print(f['email'])                                                                                                                                                                    
<input type="email" name="email" id="id_email">
View Code

  Form對象作的第二件事情是校驗數據,下面建立一個新的Form對象,測試代碼以下:

In [8]: f = ContactForm({'subject': 'hello', 'email': 'blackysy@qq.com', 'message': 'Nice site!'})                                                                                           
In [9]: f.is_valid()                                                                                                                                                                        
Out[10]: True

In [15]: f = ContactForm({'subject': 'hello', 'message': ''})                                                                                                                                
In [17]: f.is_valid()                                                                                                                                                                        
Out[17]: False
In [18]: f['message'].errors                                                                                                                                                                 
Out[18]: ['This field is required.']
View Code

(2)編寫templates/contact_form.html

   默認基礎版本的前端頁面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Contanct us</title>
</head>
<body>
    <h1>Contact us</h1>
    {% if form.errors %}
        <p style="color: red">
            Please correct the error{{ forms.errors|pluralize }} below.
        </p>
    {% endif %}

    <form action="" method="post">
       <table>
           {{ form.as_table }}
       </table>
        <input type="submit" value="Submit">
    </form>
</body>
</html>
View Code

  上面的css是默認的,實際咱們都須要自定義表單顯示,因此須要重寫,那麼每個字段部件(<input>, <select>, <textarea>)都經過調用{{ form.字段名 }}進行單獨渲染,因此咱們能夠在這裏自定義。代碼以下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Contanct us</title>
    <style type="text/css">
        .field {
            background-color: blue;
        }
        
        ul {
            margin: 0;
            padding: 0;
        }
        
        .errorlist li {
            background-color: red;
            color: white;
            display: block;
            font-size: 10px;
            margin: 0 0 3px;
            padding: 4px 5px;
        }
    </style>
</head>
<body>
    <h1>Contact us</h1>
    {% if form.errors %}
        <p style="color: red">
            Please correct the error{{ forms.errors|pluralize }} below.
        </p>
    {% endif %}

    <form action="" method="post">
       <div class="field">
           {{ form.subject.errors }}
           <label for="id_subject">Subject:</label>
           {{ form.subject }}
       </div>
        <div class="field">
           {{ form.email.errors }}
           <label for="id_email">E-mail:</label>
           {{ form.email }}
       </div>
        <div class="field">
           {{ form.message.errors }}
           <label for="id_message">Message:</label>
           {{ form.message }}
       </div>
        <input type="submit" value="Submit">
    </form>
</body>
</html>
View Code

   看起來有點難看,但驗證示例將就一下吧~~

相關文章
相關標籤/搜索