四【用django2.0来开发】后台会员管理(二) ModelForm表单的使用方法以及数据验证
上一节我们讲完了ModelAdmin的使用, 但是在操作中也发现, 新增编辑会员时, 我们无法验证数据是否正确, 比如
- 用户名、手机号、邮箱都应该是唯一的
- 用户名和密码长度的验证
- 编辑用户信息时不填写密码则不更新密码, 填写了则更新密码
- 自定义验证不通过的文案
...
这些要求, 我们就必须得使用自定义的表单来完成了
项目地址:https://gitee.com/ccnv07/django_example
Form介绍
通过表单, 我们可以实现以下的功能
- 自定义字段的样式
- 类似的表单可以通过类继承减少代码量
- 完成自定义的表单数据验证
定义表单字段
关于表单的代码我们一般放在每个模块的forms.py中
表单字段类型说明
CharField
单行文本输入字段, 对应模型的CharField字段
表单中的样式就是input type=text
max_length: 最大长度
min_length: 最小长度
strip: 是否过滤左右的空格
empty_value: 为空时的值, 默认是空字符串
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 ModelForm class 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 admin from .forms import AccountForm @admin.register(Account) class Ac b60 countAdmin(admin.ModelAdmin): form = AccountForm
在ModelAdmin中指定form参数, 就可以把表单绑定上去了。 点击新增/编辑页面, 也就可以看到表单生效了
表单数据的验证
接下来, 我们就需要完成表单提交数据以后的验证的方法了
其实在定义表单字段时, 我们就已经完成了一部分的验证了
比如
account = forms.CharField( required=True, error_messages={ 'required': '请输入用户名', }, label='用户名')
就定义了account字段必须填写, 如果出错则返回“请输入用户名”的提示
但是这个并不能完成我们所有的验证, 所以我们也可以根据字段进行自定义的验证
比如, 我要实现account用户名字段是唯一的
from django import forms from django.core.exceptions import ValidationError from .models import Account class 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.py class 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.s 16c8 cene = '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.py class 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 forms class 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来开发】后台会员管理(二) ModelAdmin 模型管理的使用方法
- django(7)modelform操作及验证、ajax操作普通表单数据提交、文件上传、富文本框基本使用
- django中ModelForm save方法 以及快速生成空表单或包含数据的表单 包含错误信息
- 使用Django Form解决表单数据无法动态刷新的两种方法
- 【用django2.0来开发】 后台会员管理
- 使用Django的ModelForm对表单进行自动验证(可自定义验证规则)
- Python中使用django form表单验证的方法
- jQuery.validator.addMethod自定义验证方法【在表单验证中的使用 $("#appEdit_Form").validate({rules : {},messages:{}】
- YII2.0 Activeform表单组件的使用方法
- MVC使用jQuery从视图向控制器传递Model,数据验证,MVC HTML辅助方法小结
- 表单包含file上传文件提交,使用ajaxSubmint或者ajaxForm 遇到的问题以及解决方法
- yii2.0 Activeform表单部分组件使用方法
- Laravel中使用FormRequest进行表单验证方法及问题汇总
- HTML5 form标签之解放表单验证、增加文件上传、集成拖放的使用方法
- Android应用开发SharedPreferences存储数据的使用方法 以及与 getPreferences 、getDefaultSharedPreferences的区别
- yii2.0 Activeform表单部分组件使用方法
- Yii Framework2.0开发教程(2)使用表单Form
- 使用Django开发一个图书管理系统----04.通过admin模块管理我们的app和model
- YII2.0 Activeform表单组件的使用方法
- 浅谈在Delphi中Dll调试方法以及怎样在Dll中使用数据模块DataModule(或表单Form)