1. 程式人生 > >Django學習筆記(6)——Form表單

Django學習筆記(6)——Form表單

采集 server spa 點擊事件 checkbox 構建 tor log fields

知識儲備:HTML表單form學習

  表單,在前端頁面中屬於最常見的一個東西了。基本上網站信息的提交都用到了表單,所以下面來學習Django中優雅的表單系統:Form

  表單的主要作用是在網頁上提供一個圖形用戶頁面,用作采集和提供用戶輸入數據。

  表單的基本結構: <form></form>

1,from表單常用屬性

  • action :表單提交的服務器地址,也就是服務器接收表單數據的url地址
  • method:表單提交數據的方法(一般為get/post)
  • name:最好是name屬性的唯一性
  • enctype:表單數據提交時使用的編碼類型,默認使用"pplication/x-www-form-urlencoded",如果使用post請求,則請求頭中的content-type指定值就是該值。如果表單中有上傳文件,編碼需要使用"multipart/form-data"類型才能完成傳遞文件數據。

1.1 提交方式 get和post

  get:使用URL傳參:http://服務器地址?name1 = value&name2=value2(?表示傳遞參數,?後面采用name=value的形式傳遞,多個參數之間,用&鏈接)URL傳參不安全,所有信息可在地址欄看到,並且可以通過地址欄隨機傳遞其他數據。URL傳遞數據量有限,只能傳遞少量數據。

  post:使用HTTP請求傳遞數據。URL地址欄不可見,比較安全。且傳遞數據量沒有限制。

表單提交中中get和post方式的區別

  • 1,get是從服務器獲取數據,post是向服務器傳送數據
  • 2,get安全性非常低,post安全性非常高
  • 3,get傳送的數據量較小,不能大於2kb,post傳送的數據量較大,一般被默認為不受限制。但是理論上,IIS4中最大量為80KB,IIS5中為100KB。
  • 4,對於get方式,服務器端用request.QueryString獲取變量的值,對於post方式,服務器端用Request.Form獲取提交的數據。

1.2 瀏覽器提交表單時,會執行如下步驟

  • 1,識別出表單中表單元素的有效項,作為提交項
  • 2,構建出一個表單數據集
  • 3,根據form表單中的enctype屬性的值作為content-type對數據進行編碼
  • 4,根據form表單中的action屬性和method屬性向指定的地址發送數據

2,input標簽

  input標簽是輸入框,是表單中最重要的部分。

2.1 表單的type屬性:

<form action="外部鏈接路徑".method="get/post".name="#">

<input type="text">輸入文本框

<input type="password">輸入密碼框

<input type="button">輸入按鈕

<input type="reset">重置

<input type="submit">提交

<input type="file">文件

<input type="checkbox">多選框

<input type="checkbox" checked>代表多選框默認選擇項

<input type="radio">單選框,註意name需一樣

<input type="date">時間

<input type="checkbox">多選框

  name:是指名字,因為提交的是鍵值對,所以必須要指定名字,否則無法提交,即使提交了也沒有意義。

  value:文本框的內容,一般用在不能輸入的類型中,如改變按鈕的名字等。

  placeholder:占位內容,通常用於顯示

  readonly:只讀模式,設置後無法修改輸入框的內容

  disabled:禁用狀態

  size:由於輸入框是單行的,所以只能設置寬度

  maxlength:限制輸入框最大輸入的字符個數

2.1 表單提交方式

  開發中表單提交是很常見的,表單的提交方式也有很多種。

1,使用submit按鈕提交表單

<input type="submit" value="提交"> 

  

2,使用button按鈕提交表單

<input type="button" value="提交"> 

  

3,使用js進行表單提交,將form表單進行標記,將form表單中的某個元素設置成點擊事件,點擊時候調用js函數,再用JS。

$("#id").submit()

  

3,label 標簽—— for 屬性

  label元素不會向用戶呈現任何特殊效果。不過,它為鼠標用戶改進了可用性。如果您在label元素內點擊文本,就會觸發此控件。也就是說,當用戶選擇該標簽時,瀏覽器就會自動將焦點轉到和標簽相關的表單控件上。

  <label> 標簽的for屬性應當與相關元素的id屬性相同

3.1 實例

  帶有兩個輸入字段和相關標記的簡單HTML表單:

技術分享圖片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <table>
        <tr>
            <td><label for="username">用戶名: </label></td>
            <td><input type="text" name="username" id="username"></td>
        </tr>
         <tr>
            <td><label for="username">密碼: </label></td>
            <td><input type="password" name="password" id="password"></td>
        </tr>
         <tr>
            <td><label for="repassword">密碼確認: </label></td>
            <td><input type="password" name="password" id="repassword"></td>
        </tr>
         <tr>
            <td><label for="_basketball">愛好: </label></td>
            <td>
                <label><input type="checkbox" value="basketball" name="‘hobby" id="_basketball">basketball</label>
                <label><input type="checkbox" value="football" name="‘hobby" id="_basketball">football</label>
                <label><input type="checkbox" value="skating" name="‘hobby" id="_basketball">skating</label>
            </td>
        </tr>

        <tr>
            <td><label for="_boy">性別:</label></td>
            <td>
                <label><input type="radio" value="boy" name="sex" id="_boy">boy</label>
                <label><input type="radio" value="girl" name="sex" >girl</label>
            </td>
        </tr>

        <tr>
            <td><label for="email">郵箱:</label></td>
            <td><input type="text" name="email" id="email"></td>
        </tr>

        <tr>
            <td><label for="address">住址:</label></td>
            <td><input type="text" name="address" id="address"></td>
        </tr>
    </table>

</body>
</html>

  

Django:表單字段和插件widgets

一,Django常用字段

Field
    required=True,               是否允許為空
    widget=None,                 HTML插件
    label=None,                  用於生成Label標簽或顯示內容
    initial=None,                初始值
    help_text=‘‘,                幫助信息(在標簽旁邊顯示)
    error_messages=None,         錯誤信息 {‘required‘: ‘不能為空‘, ‘invalid‘: ‘格式錯誤‘}
    show_hidden_initial=False,   是否在當前插件後面再加一個隱藏的且具有默認值的插件(可用於檢驗兩次輸入是否一直)
    validators=[],               自定義驗證規則
    localize=False,              是否支持本地化
    disabled=False,              是否可以編輯
    label_suffix=None            Label內容後綴
 
 
CharField(Field)
    max_length=None,             最大長度
    min_length=None,             最小長度
    strip=True                   是否移除用戶輸入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             總長度
    decimal_places=None,         小數位長度
 
BaseTemporalField(Field)
    input_formats=None          時間格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            時間間隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正則表達式
    max_length=None,            最大長度
    min_length=None,            最小長度
    error_message=None,         忽略,錯誤信息使用 error_messages={‘invalid‘: ‘...‘}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允許空文件
 
ImageField(FileField)      
    ...
    註:需要PIL模塊,pip3 install Pillow
    以上兩個字典使用時,需要註意兩點:
        - form表單中 enctype="multipart/form-data"
        - view函數中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                選項,如:choices = ((0,‘上海‘),(1,‘北京‘),)
    required=True,             是否必填
    widget=None,               插件,默認select插件
    label=None,                Label內容
    initial=None,              初始值
    help_text=‘‘,              幫助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查詢數據庫中的數據
    empty_label="---------",   # 默認空顯示內容
    to_field_name=None,        # HTML中value的值對應的字段
    limit_choices_to=None      # ModelForm中對queryset二次篩選
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   對選中的值進行一次轉換
    empty_value= ‘‘            空值的默認值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   對選中的每一個值進行一次轉換
    empty_value= ‘‘            空值的默認值
 
ComboField(Field)
    fields=()                  使用多個驗證,如下:即驗證最大長度20,又驗證郵箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象類,子類中可以實現聚合多個字典去匹配一個值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:[‘%Y--%m--%d‘, ‘%m%d/%Y‘, ‘%m/%d/%y‘]
    input_time_formats=None    格式列表:[‘%H:%M:%S‘, ‘%H:%M:%S.%f‘, ‘%H:%M‘]
 
FilePathField(ChoiceField)     文件選項,目錄下文件顯示在頁面中
    path,                      文件夾路徑
    match=None,                正則匹配
    recursive=False,           遞歸下面的文件夾
    allow_files=True,          允許文件
    allow_folders=False,       允許文件夾
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=‘‘
 
GenericIPAddressField
    protocol=‘both‘,           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1時候,可解析為192.0.2.1, PS:protocol必須為both才能啟用
 
SlugField(CharField)           數字,字母,下劃線,減號(連字符)
    ...
 
UUIDField(CharField)           uuid類型
    ...

  

二,Django內置插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

  

三,常用選擇插件——widget

  widget是form表單最重要的參數之一,指定渲染Widget時使用的widget類,舉個例子:就是說這個form字段在HTML頁面中為文本輸入框,密碼輸入框,單選框,多選框。。。。。

3.1,密碼輸入框

 pwd = forms.CharField(
        min_length=6,
        label="密碼",
        widget=forms.widgets.PasswordInput()
    

  

3.2,單radioSelect

  單radio值為字符串

 user_type_choice = (
        (0, u‘普通用戶‘),
        (2, u‘高級用戶‘),
    )
    user_type = forms.IntegerField(initial=2,
                                   widget=forms.widgets.RadioSelect(choices=user_type_choice,))

  

技術分享圖片

3.3,單選select

user_type_choice = (
        (0, u‘普通用戶‘),
        (2, u‘高級用戶‘),
    )
    user_type = forms.IntegerField(initial=2,
                                   widget=forms.widgets.Select(choices=user_type_choice,))

  

技術分享圖片

3.4,多選select

user_type_choice = (
        (0, u‘普通用戶‘),
        (2, u‘高級用戶‘),
    )
    user_type = forms.IntegerField(initial=[1, ],
                                   widget=forms.widgets.SelectMultiple(choices=user_type_choice,))

  

技術分享圖片

3.5,單選checkbox

user_type = forms.CharField(widget=forms.widgets.CheckboxInput())

  

技術分享圖片

3.6,多選checkbox

  值為列表

user_type_choice = (
        (0, u‘普通用戶‘),
        (2, u‘高級用戶‘),
    )
    user_type = forms.CharField( initial=[2, ],
                                       widget=forms.widgets.CheckboxSelectMultiple(
                                       choices=user_type_choice,
                                   ))

  

技術分享圖片

3.6 關於choice的註意事項

  在使用選擇標簽的時候,需要註意choices的選項可以從數據庫獲取,但是由於是靜態子彈,獲取的值無法更新,那麽需要自定義構造方法從而達到目的。

Django:表單實例

  首先我們看一下下面的案例:

#/usr/bin/env python
#-*- coding:utf-8 -*-
from django.shortcuts import render

# Create your views here.


def user_list(request):
    host = request.POST.get(‘host‘)
    port = request.POST.get(‘port‘)
    mail = request.POST.get(‘mail‘)
    mobile = request.POST.get(‘mobile‘)
    #這裏有個問題,如果,這個from表單有20個input,你在這裏是不是的取20次?

    #驗證:
    #輸入不能為空,並且有的可以為空有的不可以為空
    #如果email = 11123123  這樣合法嗎?
    #如果mobile = 11123123  這樣合法嗎?
    #如果ip = 11123123  這樣合法嗎?
    ‘‘‘
    你在這裏是不是需要做一大堆的輸入驗證啊?並且有很多這種頁面會存在這種情況,如果每個函數都這樣做估計就累死了
    ‘‘‘
    return render(request,‘user_list.html‘)

  針對於上面的問題,如何解決呢?——那就是Form表單

Django中form表單的作用:

  • 1,自動生成HTML表單元素
  • 2,用來做用戶提交的驗證
  • 3,檢查表單數據的合法性
  • 4,回顯功能(驗證錯誤,輸入數據不會被清空)
  • 5,數據類型轉換(轉換成相應的python類型)

  通常提交表單數據就是由HTML表單向後臺傳遞信息,後臺通過request.GET() 或者 request.POST()獲取。

一,構建一個簡單表單的流程,並提交信息給數據庫

1.1,建立一個django項目

  建一個Blog項目,並在template下新建兩個html頁面,一個註冊頁面命名為register,一個歡迎頁面為welcome。

1,創建project

django-admin startproject  Blog

2,創建APP

python  manage.py startapp  user1

3,修改settings配置

在INSTALLED_APPS中添加APP:user1

在TEMPLATES中查看“DIRS”內容,如果有template,請保持原樣,如果沒有,則添加

‘DIRS‘: [os.path.join(BASE_DIR, ‘templates‘)]

  

  項目目錄如下:

技術分享圖片

1.2, 填充HTML文件內容

  給template下兩個html頁面register和welcome填充內容。

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>register</title>
</head>
<body>

    <form action="/user/register/" method="post">

        {% csrf_token %}

        <p>用戶名:<input type="text" name="username"></p>
        <p>密碼: <input type="password" name="password"></p>
        <input type="submit" value="submit">
    </form>

</body>
</html>

  

技術分享圖片

welcome.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>welcome</title>
</head>
<body>

<h1>welcome to this page</h1>

</body>
</html>

  

1.3,在models中創建表結構

  在user1/models.py中創建表結構,代碼如下:

from django.db import models

# Create your models here.
class BlogUser(models.Model):
    username = models.CharField(max_length=200, unique=True)
    password = models.CharField(max_length=200)
    

  ChariField 字符串字段,用於較短的字符串,需要max_length來指定VARCHAR數據庫字段的大小。

  同時,修改Bolg/settings.py的內容:

找到下面這段代碼,並註釋掉:
DATABASES = {
    ‘default‘: {
        ‘ENGINE‘: ‘django.db.backends.sqlite3‘,
        ‘NAME‘: os.path.join(BASE_DIR, ‘db.sqlite3‘),
    }
}

然後寫入下面代碼:

import pymysql
pymysql.install_as_MySQLdb()

DATABASES = {
    ‘default‘: {
        # 這裏可以指定使用的數據庫類型,例如mysql
        ‘ENGINE‘: ‘django.db.backends.mysql‘,
        ‘NAME‘: ‘blog_demo‘,
        ‘USER‘:‘root‘,
        ‘PASSWORD‘:‘******‘,
        ‘HOST‘:‘localhost‘,
        ‘PORT‘:‘3306‘,
    }
}

  

  如果這裏不熟悉請參考:Django連接MySQL數據庫

  並且,映射數據庫,這一步不能忘記:

在終端創建表

1,生成同步數據庫的代碼:

python manage.py makemigrations

2,同步數據庫(也就是對數據庫執行真正的遷移動作):

python manage.py migrate

  技術分享圖片

1.4,以創建對象的方式操作數據庫

  我們重構views.py中的代碼

from django.shortcuts import render

# Create your views here.
from user1.models import  BlogUser

def register(request):
    if request.method ==‘GET‘:
        return render(request, ‘register.html‘)
    elif request.method == ‘POST‘:
        bloguser = BlogUser()
        bloguser.username = request.POST.get(‘username‘)
        bloguser.password = request.POST.get(‘password‘)
        bloguser.save()

        return render(request, ‘welcome.html‘)

  get() 中的username和password是取的register 裏的username的值。以獲取(request)註冊的信息,保存為save()。

  然後運行項目,並註冊信息,代碼如下:

1, 運行項目

python manage.py  runserver


2,在瀏覽器中輸入:

http://127.0.0.1:8000/user/register/

  然後我們註冊信息,並提交。我們可以看到上面的register.html中用戶名是唯一的,所以當我們註冊相同的名稱時候回報錯500,並且傳輸失敗。

  下面在數據庫看一下我們的註冊信息

技術分享圖片

  其中,3,5不顯示,因為我輸入了相同的用戶名。如果輸入不重復,則顯示下面界面。

技術分享圖片

二,構建一個簡單表單的流程,了解Form知識

  在上面的基礎上,我們再實現一個表單流程,繼續了解form表單的知識。

2.1,首先創建對應的視圖函數 views.py內容如下:

from django.shortcuts import render, HttpResponse

# Create your views here.
from django import forms

class LoginForm(forms.Form):
    account = forms.CharField()
    password = forms.CharField()
    email = forms.CharField()


def login(request):
    if request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            return HttpResponse("登錄成功")
    else:
        form = LoginForm()
    return render(request, ‘user6/login.html‘,{‘form‘:form})

  

2.2,建立對應的模板 login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div align="center" style="height: 400px; width: 100px;">
    <form action="#" method="post">
        {% csrf_token %}
        {{ form }}
        <button type="submit" id="sum">submit</button>
    </form>
</div>

</body>
</html>

  然後,去配置urls一些基本的配置(比如模板,路由等)。

我們直接點開login.html 內容如下:

技術分享圖片

我們打開Django項目,從127.0.0.1:8000/user6/login/ 進入,如下:

技術分享圖片

  直接訪問地址就顯示出這樣一個簡單的界面,由HTML文件可以看到並沒有js代碼對數據有效性進行驗證,我們隨機輸入賬號,密碼,郵箱,則提交,顯示登陸成功。如下:

技術分享圖片

三,定制表單

  從上面的代碼我們發現,前端一個 {{ form }} 就能做出一個完整強大的表單。但是我們只能用account password 做名稱嗎?

  不是的,這裏我們可以定制其名字,並且可以限制輸入位數等等各種操作。

3.1,如何給form表單設置自定義報錯內容

  在form裏有一個參數:error_messages 在他這裏就可以定義報錯內容

class UserInfo(forms.Form):
    # required是否可以為空,如果為False,則說明可以為空
    email = forms.EmailField(required=False,error_messages={‘required‘:u‘郵箱不能為空‘})
    # 如果required 不寫默認為Ture
    host = forms.CharField(error_messages={‘required‘:u‘主機不能為空‘})
    port = forms.CharField(error_messages={‘required‘:u‘端口不能為空‘})
    mobile = forms.CharField(error_messages={‘required‘:u‘手機不能為空‘})

  技術分享圖片

 

3.2,如何給form表單添加一個屬性

class UserInfo(forms.Form):
    # required是否可以為空,如果為False,則說明可以為空
    email = forms.EmailField(required=False,error_messages={‘required‘:u‘郵箱不能為空‘})
    # 如果required 不寫默認為Ture
    host = forms.CharField(error_messages={‘required‘:u‘主機不能為空‘})
    port = forms.CharField(error_messages={‘required‘:u‘端口不能為空‘})
    mobile = forms.CharField(error_messages={‘required‘:u‘手機不能為空‘},
                             # 這裏默認是TextInput 標簽
                            widget = forms.TextInput(attrs={‘class‘:‘form-control‘,
                                                            ‘placeholder‘:u‘手機號碼‘}))

  技術分享圖片

3.3,如何給form表單添加一個備註

class UserInfo(forms.Form):
    # required是否可以為空,如果為False,則說明可以為空
    email = forms.EmailField(required=False,error_messages={‘required‘:u‘郵箱不能為空‘})
    # 如果required 不寫默認為Ture
    host = forms.CharField(error_messages={‘required‘:u‘主機不能為空‘})
    port = forms.CharField(error_messages={‘required‘:u‘端口不能為空‘})
    mobile = forms.CharField(error_messages={‘required‘:u‘手機不能為空‘},
                             # 這裏默認是TextInput 標簽
                            widget = forms.TextInput(attrs={‘class‘:‘form-control‘,
                                                            ‘placeholder‘:u‘手機號碼‘}))
    # 我們再這裏新增一個備份
    memo = forms.CharField(required=False,
                           widget=forms.Textarea(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘備份‘}))

  同樣的HTML代碼也要新增:

    <form action="/user_list/" method="post">
        <p>主機 : {{ obj.host }}<span>{{ errors.host }}</span></p>
        <p>端口 : {{ obj.port }}<span>{{ errors.port }}</span></p>
        <p>郵箱 : {{ obj.email }}<span>{{ errors.email }}</span></p>
        <p>手機 : {{ obj.mobile }}<span>{{ errors.mobile }}</span></p>
        <p>備註:{{ obj.memo }}<span>{{ errors.memo }}</span></p>
        <input type="submit" value="submit">
    </form>

  技術分享圖片

3.4,自定義正則表達式增加判斷規則

import re
from django import forms
from django.core.exceptions import ValidationError

def mobile_validate(value):
    # 正則匹配
    mobile_re = re.compile(r‘^(13[0-9]|15[0123456789]|18[0-9]|14[57])[0-9]{8}$‘)
    if not mobile_re.match(value):
        raise ValidationError("手機號碼格式錯誤")

class UserInfo(forms.Form):
    # required是否可以為空,如果為False,則說明可以為空
    email = forms.EmailField(required=False, error_messages={‘required‘: u‘郵箱不能為空‘})
    host = forms.CharField(error_messages={‘required‘: u‘主機不能為空‘})
    port = forms.CharField(error_messages={‘required‘: u‘端口不能為空‘})
    mobile = forms.CharField(# 應用我們自己定義的規則
                           validators=[mobile_validate,],
                           error_messages={‘required‘: u‘手機不能為空‘},
                           # 這裏默認使用TextInput 標簽
                           widget=forms.TextInput(attrs={‘class‘: ‘form-control‘,
                                                         ‘placeholder‘: u‘手機號碼‘}))
    # 我們新增一個備份
    memo = forms.CharField(required=False,
                           widget=forms.TextInput(attrs={‘class‘: ‘form-control‘,
                                                         ‘placeholder‘: u‘備份‘}))


def user_list(request):
    # 創建了這個對象
    obj = UserInfo()
    if request.method == ‘POST‘:
        # 獲取用戶輸入一句話就搞定
        user_input_obj = UserInfo(request.POST)

        # 判斷用戶輸入是否合法
        if user_input_obj.is_valid():
            # 獲取用戶輸入
            data = user_input_obj.clean()
            print(data)
        else:
            # 如果發生錯誤,捕獲異常
            # 這裏原來什麽都沒寫,默認是ul的樣式,默認是as_ul(),
            # 如果我們寫成as_data()返回的就是一個原生的字符串
            # 還有一個as_json
            error_msg = user_input_obj.errors.as_data()
            # 然後把錯誤信息返回
            print(error_msg)
            # 然後把對象傳給html,在把錯誤信息傳遞過去
            return render(request, ‘user6/register.html‘, {‘obj‘: obj, ‘errors‘: error_msg,})
    # 將對象傳給html
    return render(request, ‘user6/register.html‘, {‘obj‘:obj,})

   當我們輸入不合法的時候,或者不是email格式的時候,會出現如下錯誤:

技術分享圖片

  這樣後端我們就有一套驗證的機制了,就是通過is_valid()來判斷用戶輸入是否合法!如果不合法就把返回的信息發送出去,如果合法獲取數據,繼續操作即可!

3.5,生成select標簽

class UserInfo(forms.Form):
    user_type_choice = (
        (0,u‘普通用戶‘),
        (1,u‘高級用戶‘),
    )
    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                               attrs={‘class‘:‘form-control‘}))
    # required是否可以為空,如果為False,則說明可以為空
    email = forms.EmailField(required=False,error_messages={‘required‘:u‘郵箱不能為空‘})
    # 如果required 不寫默認為Ture
    host = forms.CharField(error_messages={‘required‘:u‘主機不能為空‘})
    port = forms.CharField(error_messages={‘required‘:u‘端口不能為空‘})
    mobile = forms.CharField(error_messages={‘required‘:u‘手機不能為空‘},
                             # 這裏默認是TextInput 標簽
                            widget = forms.TextInput(attrs={‘class‘:‘form-control‘,
                                                            ‘placeholder‘:u‘手機號碼‘}))
    # 我們再這裏新增一個備份
    memo = forms.CharField(required=False,
                           widget=forms.Textarea(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘備份‘}))

  HTML內更改如下:

    <form action="/user_list/" method="post">
        <p>用戶類型:{{ obj.user_type }}<span>{{ errors.user_type }}</span></p>
        <p>主機 : {{ obj.host }}<span>{{ errors.host }}</span></p>
        <p>端口 : {{ obj.port }}<span>{{ errors.port }}</span></p>
        <p>郵箱 : {{ obj.email }}<span>{{ errors.email }}</span></p>
        <p>手機 : {{ obj.mobile }}<span>{{ errors.mobile }}</span></p>
        <p>備註:{{ obj.memo }}<span>{{ errors.memo }}</span></p>
        <input type="submit" value="submit">
    </form>

  技術分享圖片

3.6.關於後端驗證

  這個後端驗證是必須要有驗證機制的,前端可以不寫但是後端必須寫,前端的JS是可以被禁用掉的,在實際的生產環境中比如登錄和驗證的時候,我們一般都使用 JQuery+AJAX 來判斷用戶的輸入是否為空,假如JS被禁用(瀏覽器端可以設置禁用JS效果)的話,我們這個認證屏障是不是就消失了呢?(雖然一般不會禁用但是還是存在風險),所以我們一般做兩種認證,在前端做一遍認證,在後端做一遍認證。

技術分享圖片

3.7,代碼總結

import re
from django import forms
from django.core.exceptions import ValidationError

#自定義方法
def mobile_validate(value):
    mobile_re = re.compile(r‘^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$‘) #正則匹配
    if not mobile_re.match(value):
        raise ValidationError(‘手機號碼格式錯誤‘) #如果沒有匹配到主動出發一個錯誤


class UserInfo(forms.Form):

    user_type_choice = (
        (0, u‘普通用戶‘),
        (1, u‘高級用戶‘),)

    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={‘class‘:‘form-control‘}))

    email = forms.EmailField(required=True,error_messages={‘required‘:u‘郵箱不能為空‘}) #required是否可以為空,如果為False說明可以為空
    host = forms.CharField(error_messages={‘required‘:u‘主機不能為空‘}) #如果required不寫默認為Ture
    port = forms.CharField(error_messages={‘required‘:u‘端口不能為空‘})

    #默認mobile裏有一個默認為空的機制,我們在原有的參數裏增加怎們自定義的方法
    mobile = forms.CharField(validators=[mobile_validate,],#應用咱們自己定義的規則
                              error_messages={‘required‘:u‘手機不能為空‘},
                              widget=forms.TextInput(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘手機號碼‘})
                                    #這裏默認是TextInput,標簽
                              )
    #咱們在新增一個備註
    memo = forms.CharField(required=False,
                            widget=forms.Textarea(attrs={‘class‘:‘form-control‘,‘placeholder‘:u‘備註‘}))

def user_list(request):
    obj = UserInfo() #創建了這個對象
    if request.method == ‘POST‘:
        #獲取用戶輸入一句話就搞定
        user_input_obj = UserInfo(request.POST)

        if user_input_obj.is_valid(): #判斷用戶輸入是否合法
            data = user_input_obj.clean() #獲取用戶輸入
            print data
        else:
            #如果發生錯誤,捕捉錯誤
            error_msg = user_input_obj.errors.as_data()#這裏原來什麽都沒寫,默認是ul的樣式,默認是as_ul(),如果我們寫成as_data()返回的就是一個原生的字符串
            #還有一個as_json

            print error_msg #打印一下然後看下他的類型
            #然後把錯誤信息返回
            return render(request,‘user_list.html‘,{‘obj‘:obj,‘errors‘:error_msg,})#然後把對象傳給html,在把錯誤信息傳遞過去
    return render(request,‘user_list.html‘,{‘obj‘:obj,})#然後把對象傳給html

  

Form組件的鉤子

局部鉤子

def clean_username(self):  # 函數名必須已clean_字段名的格式
        user = self.cleaned_data.get("username")
        if not User.objects.filter(username=user):
            if not user.isdigit():
                if re.findall(r"^[A-Za-z0-9_\-\u4e00-\u9fa5]+$",user):
                    return user  # 通過檢測,原數據返回 self.cleaned_data.get("username")
                else:
                    raise ValidationError(‘用戶名存在非法字符‘)  # 沒通過檢測拋出錯誤,必須用ValidationError

            else:
                raise ValidationError("用戶名不能為純數字")
        else:
            raise ValidationError("該用戶名已存在")

  

全局鉤子

def clean(self):  # 必須命名為clean
        # 判斷是否都通過檢測,都不為None
        if self.cleaned_data.get("password") and self.cleaned_data.get("check_pwd"):
            if self.cleaned_data.get("password") == self.cleaned_data.get("check_pwd"):
                return self.cleaned_data  # 如果兩次密碼相同,返回幹凈的字典數據
            else:
                raise ValidationError("輸入密碼不一致")  # 沒通過檢測返回異常信息
        else:
            return self.cleaned_data

  

參考文獻:https://blog.csdn.net/qq_42068900/article/details/80904596

Django學習筆記(6)——Form表單