Django ModelForm操作及验证
一、内容回顾
Model
- 数据库操作
- 验证
class A(MOdel):
user =
email =
pwd =
Form
- class LoginForm(Form):
email = fields.EmailField()
user =
pwd =
- is_valid -> 每一个字段进行正则(字段内置正则)+clean_字段 -> clean(__all__) -> _post_clean
- cleand_data
- error
--------> 推荐Form <---------
二、ModelForm操作及验证
Model + Form ==> ModelForm。model和form的结合体,所以有以下功能:
- 数据验证
- 数据库操作
model有操作数据库的字段,form验证也有那几个字段,虽然耦合度降低,但是代码是有重复的。如果利用model里的字段,那是不是form里的字段就不用写了。
1、Model + Form (之前的操作)
models.py
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType',to_field='id')
forms.py
from django import forms
from django.forms import fields
class UserInfoForm(forms.Form):
# username = models.CharField(max_length=32) <-- models
username = fields.CharField(max_length=32)
# email = models.EmailField() <-- models
email = fields.EmailField()
# user_type = models.ForeignKey(to='UserType',to_field='id') <-- models
user_type = fields.ChoiceField(
choices=models.UserType.objects.values_list('id','caption')
)
# 下面的操作是让数据在网页上实时更新。
def __init__(self, *args, **kwargs):
super(UserInfoForm,self).__init__(*args, **kwargs)
self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')
index.html
<body>
<form action="/index/" method="POST" novalidate="novalidate">
{% csrf_token %}
{{ obj.as_p }}
<input type="submit" value="提交">
</form>
</body>
novalidate : HTML5输入类型和浏览器验证
如果表单中包含URLField、EmailField和其他整数字段类似,Django将使用url、email和number这样的HTML5输入类型。默认情况下,浏览器可能会对这些字段进行他们自身的验证,这些验证可能比Django的验证更严格。如果你想禁用这个行为,请设置form标签的novalidate属性,或者制定一个不同的字段,如TextInput。
2、ModelForm 基本操作
forms.py
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo # 与models建立了依赖关系
fields = "__all__"
views.py
def index(request):
if request.method == "GET":
obj = UserInfoModelForm()
return render(request,"index.html",{'obj':obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
print(obj.is_valid()) # 这是方法,别忘记了加括号
print(obj.cleaned_data)
print(obj.errors)
return render(request,"index.html",{'obj':obj})
自定制字段名
如何定义http上定义的字段呢,自定义写成中文的?之前的用法是在Form里写上label。Model Form定义要用verbose_name
models.py
class UserInfo(models.Model):
username = models.CharField(max_length=32, verbose_name='用户')
email = models.EmailField(verbose_name='邮箱')
user_type = models.ForeignKey(to='UserType',to_field='id', verbose_name='类型')
如果不在model里定义,在modelForm里实现,利用labels
class UserInfoModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = "__all__"
labels = {
'username':'用户名',
'email':'邮箱',
}
展示指定的列
fields = "__all__" #展示所有字段
fields = ['username','email'] # 显示指定列
exclude = ['username'] # 排除指定列
为什么modelForm里也能做验证?
form里面有is_valid
,cleaned_data
,errors
,
# Form验证:
UserInfoForm -> Form -> BaseForm( 包含is_valid等方法)
# ModelForm验证:
UserInfoModelForm -> ModelForm -> BaseModelForm -> BaseForm
3、ModelForm组件
ModelForm
a. class Meta:
model, # 对应Model的
fields=None, # 字段
exclude=None, # 排除字段
labels=None, # 提示信息
help_texts=None, # 帮助提示信息
widgets=None, # 自定义插件
error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
field_classes=None # 自定义字段类 (也可以自定义字段)
localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
如:
数据库中
2016-12-27 04:10:57
setting中的配置
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
则显示:
2016-12-27 12:10:57
b. 验证执行过程
is_valid -> full_clean -> 钩子 -> 整体错误
c. 字典字段验证
def clean_字段名(self):
# 可以抛出异常
# from django.core.exceptions import ValidationError
return "新值"
d. 用于验证
model_form_obj = XXOOModelForm()
model_form_obj.is_valid()
model_form_obj.errors.as_json()
model_form_obj.clean()
model_form_obj.cleaned_data
e. 用于创建
model_form_obj = XXOOModelForm(request.POST)
#### 页面显示,并提交 #####
# 默认保存多对多
obj = form.save(commit=True)
# 不做任何操作,内部定义 save_m2m(用于保存多对多)
obj = form.save(commit=False)
obj.save() # 保存单表信息
obj.save_m2m() # 保存关联多对多信息
f. 用于更新和初始化
obj = model.tb.objects.get(id=1)
model_form_obj = XXOOModelForm(request.POST,instance=obj)
...
PS: 单纯初始化
model_form_obj = XXOOModelForm(initial={...})
注意:导入模块名(fields、widgets)和字段名重复,所以导入时要起个别名。
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):
is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput())
class Meta:
model = models.UserInfo
fields = '__all__'
# fields = ['username','email']
# exclude = ['username']
labels = {
'username': '用户名',
'email': '邮箱',
}
help_texts = {
'username': '...'
}
widgets = {
'username': Fwidgets.Textarea(attrs={'class': 'c1'})
}
error_messages = {
'__all__':{ # 整体错误信息
},
'email': {
'required': '邮箱不能为空',
'invalid': '邮箱格式错误..',
}
}
field_classes = { # 定义字段的类是什么
# 'email': Ffields.URLField # 这里只能填类,加上括号就是对象了。
}
# localized_fields=('ctime',) # 哪些字段做本地化
4、ModelForm 数据库操作
4.1、创建数据save
如果数据验证是ok的,那么save,就直接在数据库中创建完数据了
if obj.is_valid():
obj.save() # 创建数据
在如下一对多、多对多关系中:
class UserType(models.Model):
caption = models.CharField(max_length=32)
class UserGroup(models.Model):
name = models.CharField(max_length=32)
class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType',to_field='id')
u2g = models.ManyToManyField(UserGroup)
这样的话,执行上面的obj.save()会在UserInfo表和多对多关系表里都增加数据。
views.py
def index(request):
if request.method == "GET":
obj = UserInfoModelForm()
return render(request,'index.html',{'obj': obj})
elif request.method == "POST":
obj = UserInfoModelForm(request.POST)
if obj.is_valid():
obj.save() # 等价以下三句
# instance = obj.save(False)
# instance.save()
# obj.save_m2m()
return render(request,'index.html',{'obj': obj})
4.2、save 做了哪些操作?
save源码里:
def save(self, commit=True):
""""""
if commit:
self.instance.save() # 指的当前model对象
self._save_m2m() # 指:保存m2m对象
else:
self.save_m2m = self._save_m2m
return self.instance # model 类的对象
""""""
所以instance = obj.save(False)
时,什么都不会操作。
if obj.is_valid():
instance = obj.save(False)
instance.save() # 当前对象表数据创建
obj.save_m2m() # 多对多表数据创建
# 上面这三句完成的是和上面 obj.save 一样的操作。拆开就可以自定制操作了
4.3、修改数据
修改表数据是,记得把instance
信息也传进去,不然是新建数据,而不是对某行数据进行修改。
编辑用户信息,新url方式保留默认数据
urls.py
url(r'^user_list/', views.user_list),
url(r'^edit-(\d+)/', views.user_edit),
views.py
def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type') # 这里只能是外键,多对多字段也不可以
return render(request,'user_list.html',{'li': li})
def user_edit(request, nid):
# 获取当前id对象的用户信息
# 显示用户已经存在数据
if request.method == "GET":
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj) # 把默认数据传递进去
return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
elif request.method == 'POST':
# 数据修改的信息,给数据库的哪一行做修改?
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(request.POST,instance=user_obj) # 指定给谁做修改
if mf.is_valid():
mf.save()
else:
print(mf.errors.as_json())
return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
user_list.html
<body>
<ul>
{% for row in li %}
<li>{{ row.username }} - {{ row.user_type.caption }} - <a href="/edit-{{ row.id }}/">编辑</a></li>
{% endfor %}
</ul>
</body>
user_edit.html
<body>
<form method="POST" action="/edit-{{ nid }}/">
{% csrf_token %}
{{ mf.as_p }}
<input type="submit" value="提交" />
</form>
</body>
5、ModelForm钩子、额外字段
数据验证钩子
从上面的Form
和ModelForm
中,他们都是继承了BaseForm
,而is_valid
是在BaseForm
中定义的,所以ModelForm
也能和Form
一样使用各种钩子
额外字段
像网页上的checkbox,一个月内免登陆,用提交到数据库么?这个只需要设置session和cookie就可以了。
views.py
class UserInfoModelForm(forms.ModelForm):
is_rmb = fields.CharField(widget=widgets.CheckboxInput()) # 额外字段
class Meta:
model = models.UserInfo
fields = '__all__'
6、总结
1. 生成HTML标签:class Meta: ...
2. mf = xxxModelForm(instance=ModelObj) 生成默认值
3. 额外的标签, is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput())
4. 各种验证 is_valid() -> 各种钩子...
5. mf.save()
# 或
instance = mf.save(False)
instance.save()
mf.save_m2m()
ModelForm因为model和form耦合太密切,所以一般写小程序用它。
作者:马小跳_
链接:https://www.jianshu.com/p/dee5806b27a1
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Django ModelForm操作及验证的更多相关文章
- django(7)modelform操作及验证、ajax操作普通表单数据提交、文件上传、富文本框基本使用
一.modelForm操作及验证 1.获取数据库数据,界面展示数据并且获取前端提交的数据,并动态显示select框中的数据 views.py from django.shortcuts import ...
- Django ModelForm表单验证
ModelForm 在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义 应用场景:定制model admin 的时候可以使用.适用于小业 ...
- Django(九)上:ModelForm操作
一.内容回顾 Model - 数据库操作 - 验证 class A(MOdel): user = email = pwd = Form - class LoginForm(Form): email = ...
- Python开发【Django】:ModelForm操作
ModelForm 内容回顾: Model - 数据库操作 - 验证 class A(MOdel): user = email = pwd = Form class LoginForm(Form): ...
- Django使用普通表单、Form、以及modelForm操作数据库方式总结
Django使用普通表单.Form.以及modelForm操作数据库主要应用于增删该查的情景下,流程通用如下,只是实现方式不一样: 进入填写表单页面: 在表单页面填写信息,并提交: 表单数据验证 验证 ...
- web框架-(七)Django补充---models进阶操作及modelform操作
通过之前的课程我们可以对于Django的models进行简单的操作,今天了解下进阶操作和modelform: 1. Models进阶操作 1.1 字段操作 AutoField(Field) - int ...
- python运维开发(十九)----Django后台表单验证、session、cookie、model操作
内容目录: Django后台表单验证 CSRF加密传输 session.cookie model数据库操作 Django后台Form表单验证 Django中Form一般有2种功能: 1.用于做用户提交 ...
- Django model操作
一.各种查询统计操作 def all(self) # 获取所有的数据对象 def filter(self, *args, **kwargs) # 条件查询 # 条件可以是:参数,字典,Q def ...
- Day24-ModelForm操作及验证
Day23内容回顾--缺失,遗憾成狗. 一:Model(2个功能) -数据库操作: -验证,只有一个clean方法可以作为钩子. 二:Form(专门来做验证的)--------根据form里面写的类, ...
随机推荐
- 如何获取到app的包名
相信很多朋友在刚开始接触测试app的时候都不清楚app的包名是什么,接下来给大家介绍几种方法去获取. 一.手机设备已连接到电脑,点击进入app中,前提是电脑上装备了android-SDK,tools文 ...
- hdu4507 吉哥系列故事——恨7不成妻[数位DP]
这题面什么垃圾玩意儿 首先看到问题格式想到数位DP,但是求的是平方和.尝试用数位DP推出. 先尝试拼出和.设$f[len][sum][mod]$表示填到$len$位,已填位置数位和$sum$,数字取余 ...
- 创建Windows任务计划定时调用网页执行任务(通过Windows PowerShell的Invoke-WebRequest实现)
前言:项目中使用RoadFlow工作流,设置超时自动提交功能,自动提交功能已有现成的网页可实现(http://127.0.0.1/WorkFlowRun/AutoSubmit),现需创建Windows ...
- 开始PHP,常量/变量与内存间的关系--传值
一.常见的PHP代码嵌入式方式,与html结合 要注意:文件名后缀必须形如xxx.php否则html将无法解析 二.php脱离html代码独立工作,没有其他代码 不需要借助Apache工作,只需要ph ...
- 29. ClustrixDB 分布式架构/并发控制
介绍 ClustrixDB使用多版本并发控制(MVCC)和2阶段锁(2PL)的组合来支持混合的读写工作负载.在我们的系统中,读取器享受无锁快照隔离,而写入器使用2PL来管理冲突.并发控制的组合意味着读 ...
- Jquery实现div左右重复来回走动
<!DOCTYPE HTML><html><head> <meta charset=utf-8 /> <title>UFO来了</ti ...
- Nowcoder 练习赛26 D xor序列 ( 线性基 )
题目链接 题意 : 中文题.点链接 分析 : 对于给定的 X 和 Y 假设存在一个 Z 使得 X (xor) Z = Y 做一个变形 X (xor) Z (xor) Y = 0 X (xor) Y = ...
- Travis CI Could not find or load main class org.gradle.wrapper.GradleWrapperMain 错误
问题 在 Travis CI 编译的时候出现 Error: Could not find or load main class org.gradle.wrapper.GradleWrapperMain ...
- HGOI20190812 省常中互测5
Task 1 辩论 有N 个参加辩论的候选人,每个人对这两个议题都有明确的态度,支持或反对.作为组织者,小D 认真研究了每个候选人,并给每个人评估了一个非负的活跃度,他想让活跃度之和尽可能大.选出的候 ...
- HGOI20190808 省常中互测1
Problem A sum 给出$n$个元素的序列$\{a_i\}$,求出两个不相交连续子序列的最大元素和. 即对于$1 \leq A \leq B \leq C \leq D \leq n$最大化 ...