四【用django2.0來開發】後台會員管理(二) ModelForm表單的使用方法以及資料驗證

來源:互聯網
上載者:User

標籤:就是   多表   綁定   status   並且   delete   技術   war   none   

上一節我們講完了ModelAdmin的使用, 但是在操作中也發現, 新增編輯會員時, 我們無法驗證資料是否正確, 比如

  1. 使用者名稱、手機號、郵箱都應該是唯一的
  2. 使用者名稱和密碼長度的驗證
  3. 編輯使用者資訊時不填寫密碼則不更新密碼, 填寫了則更新密碼
  4. 自訂驗證不通過的文案
    ...

這些要求, 我們就必須得使用自訂的表單來完成了

項目地址:https://gitee.com/ccnv07/django_example

Form介紹

通過表單, 我們可以實現以下的功能

  1. 自訂欄位的樣式
  2. 類似的表單可以通過類繼承減少代碼量
  3. 完成自訂的表單資料驗證
定義表單欄位

關於表單的代碼我們一般放在每個模組的forms.py中

表單欄位類型說明

CharField
單行文本輸入欄位, 對應模型的CharField欄位
表單中的樣式就是input type=text
max_length: 最大長度
min_length: 最小長度
strip: 是否過濾左右的空格
empty_value: 為空白時的值, 預設是Null 字元串

EmailField
郵箱輸入文字欄位, 對應模型的EmailField欄位
標案中是input type=text
但是會自動增加一個郵箱格式的校正

ChoiceField
下拉單選欄位, 這個在模型中是沒有的
對應表單的select標籤
choices參數也是二維元組的格式

BooleanField
選擇欄位, 對應表單中的checkbox

DateField
日期選擇欄位
input_formats: 定義時間格式, 預設是:

[‘%Y-%m-%d‘,      # ‘2006-10-25‘ ‘%m/%d/%Y‘,      # ‘10/25/2006‘ ‘%m/%d/%y‘]      # ‘10/25/06‘

DateTimeField
日期時間欄位, 同DateField

TimeField
時間欄位, 同DateField

DecimalField
十進位數字欄位
max_value: 最大值
min_value: 最小值
max_digits: 前置0被去除後的最大位元
decimal_places: 允許的小數位的長度

FileField
檔案上傳欄位

IntegerField
整數欄位
max_value: 最大值
min_value: 最小值

剩下還有很多表單欄位類型, 在之後的教程中再繼續介紹, 目前這些, 就算是比較常見的欄位了

通過介紹以後, 大家發現, 我沒說最常見的PasswordField, 其實django的表單中就沒有這個欄位類型, 那麼, 如何?密碼欄位呢?

password = forms.CharField(widget=forms.PasswordInput(),max_length=12,min_length=6, strip=True,        help_text=‘編輯時為空白則不更改密碼‘)

通過制定widget參數為forms.PasswordInput(), 就可以實現密碼欄位了

所以其實並不是Form類來規定表單欄位的類型, 而是widget來實現的表單欄位的類型, 對於每種表單欄位的類型, django都有對應的模板, 通過欄位的參數, 產生對應的html代碼

表單欄位的通用參數

label: 表單欄位的label標籤的名稱
widget: 指定此欄位採用的欄位樣式類型
help_text: 欄位的協助文本

表單的Meta 元類

只有ModelForm才有元類, Form是不需要元類的
以下是一個元類的例子

from django.forms import ModelFormclass Meta:        model = Account        # 使用自訂的Form, 就必須指定fields or exclude屬性, 否則報錯        fields = (‘account‘, ‘password‘, ‘email‘, ‘phone‘, ‘status‘)        error_messages = {            NON_FIELD_ERRORS: {                ‘unique_together‘: "%(model_name)s‘s %(field_labels)s are not unique.",            }        }

model: 指定ModelForm綁定的模型
fields: 指定後台新增編輯時要顯示的欄位
error_messages: 指定通用的錯誤資訊文案

其他還有一些複雜的操作, 會在之後的教程中詳細講解。現在我們的一個表單就完成了

將表單綁定到ModelAdmin中

但是如果想讓表單在後台中生效, 就需要把表單綁定到ModelAdmin上

from django.contrib import adminfrom .forms import AccountForm@admin.register(Account)class AccountAdmin(admin.ModelAdmin):    form = AccountForm

在ModelAdmin中指定form參數, 就可以把表單綁定上去了。 點擊新增/編輯頁面, 也就可以看到表單生效了

表單資料的驗證

接下來, 我們就需要完成表單提交資料以後的驗證的方法了
其實在定義表單欄位時, 我們就已經完成了一部分的驗證了
比如

 account = forms.CharField(        required=True, error_messages={            ‘required‘: ‘請輸入使用者名稱‘,        }, label=‘使用者名稱‘)

就定義了account欄位必須填寫, 如果出錯則返回“請輸入使用者名稱”的提示

但是這個並不能完成我們所有的驗證, 所以我們也可以根據欄位進行自訂的驗證
比如, 我要實現account使用者名稱欄位是唯一的

from django import formsfrom django.core.exceptions import ValidationErrorfrom .models import Accountclass AccountForm(forms.ModelForm):    ...省略代碼    def clean_account(self):        _info = Account.objects.filter(account=self.cleaned_data[‘account‘],                is_deleted=0).values(‘id‘)        if _info:            raise ValidationError(‘使用者已存在‘)        return self.cleaned_data[‘account‘]

當我們執行form.is_valid()方法進行驗證時, django的form類會依次執行clean_欄位名的自訂驗證方法, 如果有拋出異常(raise ValidationError(‘使用者已存在‘)), 則中斷並返回錯誤, 否則讀取到clean_欄位名的方法的傳回值, 並且寫入到cleaned_data這個字典中

根據同樣的方法, 我們也可以寫出來對email和phone欄位的驗證

在ModelAdmin操作Form

以上已經基本能實現我們的功能了, 但是在背景操作中, 新增和編輯用的是同一個表單, 如果我們需要針對新增和編輯的不同情境, 進行一些不同的操作, 就比較麻煩了。
所以我們需要通過在ModelAdmin中, 對Form進行一定的操作, 似的Form可以完成更多的判斷

# account/admin.pyclass AccountAdmin(admin.ModelAdmin):    def get_form(self, request, obj=None, **kwargs):        form = super(AccountAdmin, self).get_form(request, obj=obj, **kwargs)        # obj 儲存的是models.Account的資訊        # 根據是否有pk, 來賦予form不同的情境, 根據不同的情境可以進行不同的驗證        if (obj is not None):            form.id = obj.pk            form.scene = ‘update‘        else:            form.scene = ‘insert‘        return form

get_form方法的參數request儲存的是HttpRequest操作對象
而obj是當前操作的資料模型對象(Model), 而且在新增的操作時, obj是None, 只有在編輯時, 才存在obj

form = super(AccountAdmin, self).get_form(request, obj=obj, **kwargs) 會返回當前操作的form對象
如果obj不是None, 則當前操作是編輯, 我們就可以給form增加一個自訂的屬性scene(情境) = ‘update‘, 否則就是新增

並且我們在Form表單中, 可以針對不同的情境, 進行不同的驗證判斷

# account/forms.pyclass AccountForm(forms.ModelForm):    def clean_account(self):        # 自動驗證account欄位        if self.scene == ‘insert‘:            _info = Account.objects.filter(                account=self.cleaned_data[‘account‘],                is_deleted=0).values(‘id‘)        elif self.scene == ‘update‘:            _info = Account.objects.filter(~Q(id=self.id) & Q(                account=self.cleaned_data[‘account‘]) & Q(                    is_deleted=0)).values(‘id‘)        if _info:            raise ValidationError(‘使用者已存在‘)        return self.cleaned_data[‘account‘]

這個驗證的意思是, 如果當前情境(self.scene)是insert, 就只按照account查詢, 如果是update, 則增加id不為當前操作id的過濾條件

Django的密碼加密方法

django.contrib.auth.hashers 有兩個關於密碼加密的操作方法
make_password和check_password

make_password 是將指定的純文字密碼加密
check_password 是校正給出的純文字密碼是否正確

新增與編輯操作下密碼框的不同操作

當新增使用者時, 密碼框必填, 當編輯時, 密碼框非必填。如果填了, 則修改密碼, 如果沒填, 則不更改密碼

第一步, 我們在校正輸入的密碼時, 同時也需要實現對密碼的加密(畢竟資料庫被人破解了, 後台還是很嚴重的)

from django import formsclass AccountForm(forms.ModelForm):    def clean_password(self):        # 自動驗證密碼欄位        if self.scene == ‘insert‘:            if not self.cleaned_data[‘password‘]:                raise ValidationError(‘請輸入密碼‘)        elif self.scene == ‘update‘:            if not self.cleaned_data[‘password‘]:                return None            else:                return self.cleaned_data[‘password‘]        return make_password(self.cleaned_data[‘password‘])

這個也很好理解, 如果新增使用者時, 未輸入密碼, 則返回錯誤
更新時沒有輸入密碼, 則返回None
如果輸入, 就返回make_password加密後的密碼字串

根據之前教程的scene情境參數的指定, 就可以跟容易的實現這個功能, 但是在編輯時, 如果密碼為空白不填的話, 密碼居然也會被設定為空白。

這個是因為, 如果不填寫密碼, 的model對象會把password=None一直帶著, 轉換為sql執行時, 就變成password=‘‘了

所以, 如果password沒有輸入值, 我們就要在執行儲存之前, 幹掉model攜帶的password, 這樣才正確。

重寫ModelAdmin的儲存方法

class AccountAdmin(admin.ModelAdmin):    def save_model(self, request, obj, form, change):        if form.cleaned_data[‘password‘] is None:            del obj.password        super().save_model(request, obj, form, change)

form.cleaned_data中就是表單提交後驗證過的資料, 如果password是None, 就del掉, 然後調用父類的save_model方法, 繼續執行儲存操作。

四【用django2.0來開發】後台會員管理(二) ModelForm表單的使用方法以及資料驗證

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.