1. 程式人生 > >Django基礎(5): 表單forms的設計與使用

Django基礎(5): 表單forms的設計與使用

Django網路應用開發的5項基礎核心技術包括和Form(表單)的使用。今天小編我就來拼個老命給你來介紹下第五項Django核心基礎知識之表單forms的設計與使用吧, 並重點介紹下表單的驗證想持續瞭解後續Django Web開發技術請訂閱我的公眾號【Python與Django大咖之路】。

什麼是表單?何時使用表單?

在web開發裡表單的使用必不可少。表單用於讓使用者提交資料或上傳檔案,表單也用於讓使用者編輯已有資料。Django的表單Forms類的作用是把使用者輸入的資料轉化成Python物件格式,便於後續操作(比如儲存,修改)。

自定義表單

類似模型,Django表單也由各種欄位組成。表單可以自定義,也可以由模型Models建立。值得注意的是模型裡用的是verbose_name來描述一個欄位, 而表單用的是label。

下面是兩個ContactForm的例子。一個自定義,一個從Model建立。

from django import forms
from .models import Contact


class ContactForm1(forms.Form):
   
   name = forms.CharField(label="Your Name", max_length=255)
   email = forms.EmailField(label="Email address")


class ContactForm2(forms.ModelForm):
   
   class Meta:
       model = Contact
       fields = ('name'
, 'email',)

Django的常用做法是在app資料夾下建立一個forms.py,專門存放app中所定義的各種表單,這樣方便集中管理表單。如果要使用上述表單,我們可以在檢視views.py裡把它們像模型一樣import進來直接使用。

表單例項化

下面方法可以例項化一個空表單,但裡面沒有任何資料,可以通過 {{ form }}在模板中渲染。

form = ContactForm()

使用者提交的資料可以通過以下方法與表單結合,生成與資料結合過的表單(Bound forms)。Django只能對Bound forms進行驗證。

form = ContactForm(data=request.POST, files=
request.FILES)

模板檔案中使用form

模板檔案中我們可以通過{{ form.as_p }}{{ form.as_li }} 和 {{ form.as_table }}中渲染表單。如果你想詳細控制每個field的格式,你可以採取以下方式。

{% block content %}
<div class="form-wrapper">
  <form method="post" action="" enctype="multipart/form-data">
     {% csrf_token %}
     {% for field in form %}
          <div class="fieldWrapper">
       {{ field.errors }}
       {{ field.label_tag }} {{ field }}
       {% if field.help_text %}
            <p class="help">{{ field.help_text|safe }}</p>
       {% endif %}
          </div>
       {% endfor %}
     <div class="button-wrapper submit">
        <input type="submit" value="Submit" />
     </div>
  </form>
</div>
{% endblock %}

表單實際使用案例

我們現在需要設計一個表單讓使用者完成註冊。我們先在app目錄下新forms.py, 然後建立一個RegistrationForm。程式碼如下:

from django import forms
from django.contrib.auth.models import User


class RegistrationForm(forms.Form):

   username = forms.CharField(label='Username', max_length=50)
   email = forms.EmailField(label='Email',)
   password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
   password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)

當然你也可以不用新建forms.py而直接在html模板裡寫表單,但我並不建議這麼做。用forms.py的好處顯而易見: 

  • 所有的表單在一個檔案裡,非常便於後期維護,比如增添或修訂欄位。

  • forms.py可通過clean方法自定義表單驗證,非常便捷(見後文)。

我們使用RegistrationForm的檢視views.py是這樣子的。

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from .forms import RegistrationForm
from django.http import HttpResponseRedirect



def register(request):
   if request.method == 'POST':

       form = RegistrationForm(request.POST)
       if form.is_valid():
           username = form.cleaned_data['username']
           email = form.cleaned_data['email']
           password = form.cleaned_data['password2']
           # 使用內建User自帶create_user方法建立使用者,不需要使用save()
           
user = User.objects.create_user(username=username, password=password, email=email)
           # 如果直接使用objects.create()方法後不需要使用save()
           return HttpResponseRedirect("/accounts/login/")

   else:
       form = RegistrationForm()

   return render(request, 'users/registration.html', {'form': form})

模板是registration.html這樣子的。如果你需要通過表單上傳圖片或檔案,一定不要忘了給form加enctype="multipart/form-data"屬性。

<form action=”.” method=”POST”>
{{ form.as_p }}
</form>

我們來看下RegistrationForm是怎麼工作的:

  • 當用戶通過POST方法提交表單,我們將提交的資料與RegistrationForm結合,然後驗證表單RegistrationForm的資料是否有效。

  • 如果表單資料有效,我們先用Django User模型自帶的create_user方法建立user物件,再建立user_profile。使用者通過一張表單提交資料,我們實際上分別儲存在兩張表裡。

  • 如果使用者註冊成功,我們通過HttpResponseRedirect方法轉到登陸頁面

  • 如果使用者沒有提交表單或不是通過POST方法提交表單,我們轉到註冊頁面,生成一張空的RegistrationForm

表單的驗證

每個forms類可以通過clean方法自定義表單驗證。如果你只想對某些欄位進行驗證,你可以通過clean_欄位名方式自定義表單驗證。如果使用者提交的資料未通過驗證,會返回ValidationError,並呈現給使用者。如果使用者提交的資料有效form.is_valid(),則會將資料儲存在cleaned_data裡。

在上述使用者註冊的案例裡,我們在RegistrationForm通過clean方法添加了使用者名稱驗證,郵箱格式驗證和密碼驗證。程式碼如下。

from django import forms
from django.contrib.auth.models import User
import re


def email_check(email):
   pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}][email protected]\w+\.\w+)\"?")
   return re.match(pattern, email)


class RegistrationForm(forms.Form):

   username = forms.CharField(label='Username', max_length=50)
   email = forms.EmailField(label='Email',)
   password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
   password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)

   # Use clean methods to define custom validation rules

   
def clean_username(self):
       username = self.cleaned_data.get('username')

       if len(username) < 6:
           raise forms.ValidationError("Your username must be at least 6 characters long.")
       elif len(username) > 50:
           raise forms.ValidationError("Your username is too long.")
       else:
           filter_result = User.objects.filter(username__exact=username)
           if len(filter_result) > 0:
               raise forms.ValidationError("Your username already exists.")

       return username

   def clean_email(self):
       email = self.cleaned_data.get('email')

       if email_check(email):
           filter_result = User.objects.filter(email__exact=email)
           if len(filter_result) > 0:
               raise forms.ValidationError("Your email already exists.")
       else:
           raise forms.ValidationError("Please enter a valid email.")

       return email

   def clean_password1(self):
       password1 = self.cleaned_data.get('password1')

       if len(password1) < 6:
           raise forms.ValidationError("Your password is too short.")
       elif len(password1) > 20:
           raise forms.ValidationError("Your password is too long.")

       return password1

   def clean_password2(self):
       password1 = self.cleaned_data.get('password1')
       password2 = self.cleaned_data.get('password2')

       if password1 and password2 and password1 != password2:
           raise forms.ValidationError("Password mismatch. Please enter again.")

       return password2

通用視圖裡使用表單

在Django基於類的檢視(Class Based View)裡使用表單也非常容易,只需定義form_class就好了。下面是一個建立一篇新文章的例子。


from django.views.generic.edit import CreateView
from .models import Article
from .forms import ArticleForm


class ArticleCreateView(CreateView):
   model = Article
   form_class = ArticleForm
   template_name = 'blog/article_create_form.html'

自定義表單輸入的widget

Django forms的每個欄位你都可以選擇你喜歡的輸入widget,比如多選,複選框。你還可以定義每個widget的css屬性。如果你不指定,Django會使用預設的widget,有時比較醜。

比如下面這段程式碼定義了表單姓名欄位的輸入控制元件為Textarea,還指定了其樣式css。

from django import forms


class ContactForm(forms.Form):
   name = forms.CharField(
       max_length=255,
       
widget=forms.Textarea(
           attrs={'class': 'custom'},
       
),
   
)

設定widget可以是你的表單大大美化,方便使用者選擇輸入。比如下面案例裡對年份使用了SelectDateWidget,對課程使用RadioSelect, 顏色則使用了複選框CheckboxSelectMultiple

from django import forms

BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
COLORS_CHOICES = (
   ('blue', 'Blue'),
   
('green', 'Green'),
   
('black', 'Black'),
)

class SimpleForm(forms.Form):
   birth_year = forms.DateField(widget=forms.SelectDateWidget(years=list(BIRTH_YEAR_CHOICES)))
   favorite_colors = forms.MultipleChoiceField(
       required=False,
       
widget=forms.CheckboxSelectMultiple,
       
choices=list(COLORS_CHOICES),
   
)

表單資料初始化

有時我們需要對錶單設定一些初始資料,我們可以通過initial方法,如下所示。

form = ContactForm(
   initial={
       'name': 'First and Last Name',
   
},)

其編輯修改類應用場景中,我們還要給表單提供現有物件的資料,而不是渲染一張空表單,這時我們可這麼做。該方法僅適用於由模型建立的ModelForm,而不適用於自定義的表單。

contact = Contact.objects.get(id=1)
form =  ContactForm(instance = contact)

對於自定義的表單,可以設定default_data。

default_data = {'name': 'John', 'email': '[email protected]', }
form = ContactForm(default_data)

Formset的使用

有的時候使用者需要在1個頁面上使用多個表單,比如一次性提交新增多本書的資訊,這時我們可以使用formset。這是一個表單的集合。

建立一個FormSet我們可以這麼做:

from django import forms


class BookForm(forms.Form):
   name = forms.CharField(max_length=100)
   title = forms.CharField()
   pub_date = forms.DateField(required=False)


# forms.py - build a formset of books

from django.forms import formset_factory
from .forms import BookForm

# extra: 額外的空表單數量
# max_num: 包含表單數量(不含空表單)

BookFormSet = formset_factory(BookForm, extra=2, max_num=1)

在檢視檔案views.py裡,我們可以像使用form一樣使用formset。

# views.py - formsets example.
from .forms import BookFormSet
from django.shortcuts import render

def manage_books(request):
   if request.method == 'POST':
       formset = BookFormSet(request.POST, request.FILES)
       if formset.is_valid():
           # do something with the formset.cleaned_data
           
pass
   else
:
       formset = BookFormSet()
   return render(request, 'manage_books.html', {'formset': formset})

模板裡可以這樣使用formset。

<form action=”.” method=”POST”>
{{ formset }}
</form>

後續我們會專門介紹formset的使用案例。欲知更多Python Web開發與Django實戰案例,請關注我們的微信公眾號【Python與Django大咖之路】。

相關推薦

Django基礎(5): forms設計使用

Django網路應用開發的5項基礎核心技術包括,,,和Form(表單)的使用。今天小編我就來拼個老命給你來介紹下第五項Django核心基礎知識之表單forms的設計與使用吧, 並重點介紹下表單的驗證。想

Django中的(forms.Form)

Django中的表單: 1、HTML中的表單:用來提交資料給伺服器的,不管後臺的伺服器用的是Django還是PHP語言還是其他語言 2、Django中的表單: ①渲染表單模板 ②表單驗證資料是否合法 3、Django中表單使用流程: ①app下新建fo

Django基礎(11): 集合Formset的高階用法詳解

Formset(表單集)是多個表單的集合。Formset在Web開發中應用很普遍,它可以讓使用者在同一個頁面上提交多張表單,一鍵新增多個數據,比如一個頁面上新增多個使用者資訊。今天小編我就介紹下Django Formset的基礎知識,Formset的分類以及如何使用Forms

JavaScript基礎 submit按鈕配合form的onsubmit實現的提交驗證

java asc body bmi 是我 技術 pos true value 鎮場詩:    清心感悟智慧語,不著世間名與利。學水處下納百川,舍盡貢高我慢意。    學有小成返哺根,願鑄一良心博客。誠心於此寫經驗,願見文者得啟發。—————————————————————

JavaScript基礎 submit按鈕結合onclick事件 實現的提交驗證

ret vs2015 基礎 result oct 學習資源 charset 簡單 添加 鎮場詩:    清心感悟智慧語,不著世間名與利。學水處下納百川,舍盡貢高我慢意。    學有小成返哺根,願鑄一良心博客。誠心於此寫經驗,願見文者得啟發。————————————————

html標簽設計

多行文本 表單 off inpu 域名 type cti blog 允許 1<form>標記及其屬性 表單使用<form>和</form>來定義的,<form>標記有屬性:name、method、action、target等屬

Django從models建立(forms)

https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/ = ModelForm 對於對映到model的表單,避免重複定義屬性,Django提供了一個幫助函式讓你從一個Model直接建立Form. from

AngulairJS輸入驗證mvc

oot 表單 名稱 操作 數據庫 root min 位置 input AngulairJS表單輸入驗證 1.表單中,常用的驗證操作有:$dirty 表單有填寫記錄、$valid 字段內容合法的、$invalid 字段內容是非法的、$pristine 表單沒有填寫記錄、$er

django中處理的經典流程

contex 用戶 通過 eth ret span quest con 信息 def form_process_view(request): if request.method == ‘POST‘: # 請求為 POST,利用用戶提交的數據構造一個

tp的提交驗證

地址 更多 php end user func 機制 etc spa 一、控制器如下 引用use app\index\model\User; //註意模型類名不能和控制器類名相同 public function index(){ return $this->fe

驗證,多語言支持,CI

加載 load for 控制器 cati 驗證 pan conf span 表單驗證將漢化包,復制到application文件夾下的language,然後在config.php中,將語音改為simplified-chinese,和漢化包文件夾的名字一致。 對於隨漢化包帶來

Django--分頁器(paginator)、Django的用戶認證、Django的FORM

modelform 從數據 submit fields 個人 select method rtc 無法使用 分頁器(paginator) >>> from django.core.paginator import Paginator >>&g

Django-Django的form

valid blog pos ges 驗證 錯誤 form表單 技術分享 orm 註冊頁面如果用ajax來做,視圖views裏面判斷會很復雜,需要判斷各種字段,我們用form來做 form_obj,實例化form_post(form_obj)對象,一定要加上(reque

Django基礎2---url控制器模塊views視圖模塊

appname OS 技術分享 正則表達 什麽 url art clock pycha url控制器: 主要是用於url的分發功能,如用戶輸入:127.0.0.1:8080/apptest 配置url才能使django正確識別用戶的輸入 未配置url報錯類型如下:

Django使用普通、Form、以及modelForm操作數據庫方式總結

信息 自定義字段 turn html 缺點 tin 顯示時間 流程 req Django使用普通表單、Form、以及modelForm操作數據庫主要應用於增刪該查的情景下,流程通用如下,只是實現方式不一樣: 進入填寫表單頁面; 在表單頁面填寫信息,並提交; 表單數

71、Django之form

protoc valid init title except Go doc 列表 ima Form介紹 我們之前在HTML頁面中利用form表單向後端提交數據時,都會寫一些獲取用戶輸入的標簽並且用form標簽把它們包起來。 與此同時我們在好多場景下都需要對用戶的輸入做校驗

[Django學習] Django基礎(5)_優化分頁器

優化 最小值 src div img == cti css style 一. 基本樣式 主要優化內容: #1. 當前頁高亮 #2. 顯示當前頁及其前後兩頁 #3. 顯示省略號標記 #4. 顯示首尾頁 #5. 將“頁數描述文字”放置在“頁碼欄”下方 #6. “頁碼欄”與“

JEPLUS之APP頁面設計——JEPLUS軟件快速開發平臺

查看 title bold water back get mage pan eight JEPLUS之APP表單頁面設計 在之前的文章中我介紹了APP裏面的列表頁面設計,今天我來介紹下APP裏面的表單頁面設計。一、效果展示二、功能詳解3

Django---簡單接受信息

inpu sele opp div color etl 表單 req class 普通接受信息: 接受單選的值:例如:input select 等提交過來的信息 u = request.POST.get(‘username‘,None) 接受多選: h = reque

隱藏域display:none

隱藏域 display code idt 兩種 log 提交 點擊事件 rip 有時候前端進行表單填寫是分步驟的,每一步的時候其他步驟相關的表單視圖不可見; 針對"不可見",以下有兩種處理方式: ①display:none 這種方式呢,比較簡單,就是將三個步驟分3個d