1203 forms组件
多对多三种创建方式
forms校验性组件
django settings源码
昨日内容
ajax结合sweetalert
自己写一个删除按钮的确认框
去github上下载sweetalert源码 你只需要使用里面dist文件夹
gitlab
公司自己搭建
码云
参考示例书写即可
二次开发能力
基于人家已经写好的功能修改
1.先看别人的配置参数
2.前期就是猜
3.整体修改
linux
redis
mongodb
github
git
批量处理
bulk_create()
当你要批量操作数据库的时候 一定要减少走数据库的频率
数据的分页展示
django其实有内置的分页模块
但是该模块不好用,书写麻烦,功能不健全
自定义分页
1.queryset支持切片操作
2.研究当前页 每页展示多少条数据 起始位置 终止位置
3.前端代码不一定非要在前端书写 后端也可以
把自定义的代码拷贝到本地
基本使用
将代码放入到一个py文件中
导入该文件中的类
1.生成该类的对象
展示数据的总条数
用户想访问的页码
默认参数每页展示几条数据
分页页码的个数 奇数位
2.前端使用
qeuryset部分
|safe
多对多三种创建方式
封装程度越高,可扩展性越差
1.全自动
一般情况下
class Book(models.Model):
title = models.CharField(max_length=32)
# 多对多字段
authors = models.ManyToManyField(to='Authors')
class Authors(models.Model):
name = models.CharField(max_length=32)
好处
- 自始至终你都没有操作第三张表,全部都是有orm自动帮你创建
- 内置了四个操作第三张表的方法
- add
remove
set
clear
- add
缺点
- 自动创建的第三张表无法扩展和修改字段,表的扩展性较差
2.纯手动
了解
class Book(models.Model):
title = models.CharField(max_length=32)
class Authors(models.Model):
name = models.CharField(max_length=32)
# 自建第三张表
class Book2Authors(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Authors')
# 可以手动创建第三张表中的字段
create_time = models.DateField(auto_now_add=True)
好处
- 第三张表中字段个数和字段名称全都可以自己定义
缺点
- 不再支持orm跨表查询,没有正反向的概念
- 不能使用修改字段方法
- add
remove
set
clear
- add
3.半自动through='',through_fields=(外键字段)
推荐使用
# 半自动
class Book(models.Model):
title = models.CharField(max_length=32)
# 多对多关系字段
authors = models.ManyToManyField(to='Authors',through='Book2Authors',through_fields=('authors','book'))
class Authors(models.Model):
name = models.CharField(max_length=32)
# 自建第三张表
class Book2Authors(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Authors')
# 该表中有任意多的外键字段
through='第三张表名'
指定了不自动创建,手动创建的第三张表名,并与之关联through_fields=('','')
指定了第三张表中的到底哪两个字段维护表之间多对多关系,外键在哪,哪个字段在前面
当你的ManyToMany只有一个参数to的情况下orm会自动帮你创建第三张表
如果你加了throug和through_fields那么orm就不会自动帮你创建第三张表,但是他会在内部帮你维护关系,让你能够继续使用orm的跨表查询
through 自己制定第三张表关系
through_fields 自己制定第三张表中到底哪两个字段维护这表与表之间的多对多关系,外键在哪个表中,参数放在前面
好处
- 可以任意的添加和修改第三张表中的字段
- 支持orm跨表查询
缺点
- 不支持表字段的修改方法
- add
remove
clear
set
forms组件
1.简单引入
需求:
注册页面,获取用户输入的用户名和密码
提交到后端之后,后端需要对用户名和密码进行校验
用户名中不能含有'金 瓶 梅'
密码不能少于三位
如果不符合,展示响应的错误信息
views
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
def register(request):
# get请求来的时候直接走的是空值字典
errors = {'username':'','password':''}
# 当请求方式是post时给字典赋值
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if '金 瓶 梅' in username:
errors['username'] = '不符合社会主义核心价值观'
if len(password) < 4:
errors['password'] = '注意注意太少了'
return render(request,'register.html',locals())
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>简易校验用户的输入功能</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<link rel="stylesheet" href="bootstrap-3.3.7-dist/css/bootstrap.min.css">
<script src="bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
<form action="" method="post">
<p>username
<input type="text" name="username">
<span style="color: red">{{ errors.username }}</span>
</p>
<p>password
<input type="text" name="password">
<span style="color: red">{{ errors.password }}</span>
</p>
<input type="submit">
</form>
</body>
</html>
以上代码简单做到的事
- 手动书写html代码获取用户输入 -- 渲染标签
- 将数据传递给后端做数据校验 -- 校验数据
- 如果有数据错误,你还展示了错误信息 -- 展示信息
2.forms组件作用
能够做的事情就是上面的三步
- 渲染标签
- 校验数据
- 展示信息
使用forms组件的第一步,必须先写一个类
from django import forms
from django import forms
class MyForm(forms.Form):
# username字段 最少三位,最多八位
username = forms.CharField(max_length=8,min_length=3)
# password字段 最少三位,最多八位
password = forms.CharField(max_length=8,min_length=3)
# email字段 必须是邮箱格式
email = forms.EmailField()
测试用pycharm
右下角 python console
自动创建测试环境
2.1 校验数据
实例化创建的类,传入字典,字典中是需要校验的数据,获得对象form_obj
form_obj = views.MyForm({'username':'jason','password':'12','email':'123'})
1.is_vaild
查看是否合法
form_obj.is_valid()
False # 只有当你的数据全部符合校验规则的情况下 结果才是True 否则都为False
2..errors
查看不符合的字段及原因
form_obj.errors
{
'password': ['Ensure this value has at least 3 characters (it has 2).'],
'email': ['Enter a valid email address.']
}
3.cleaned_data
查看符合的数据
form_obj.cleaned_data
{'username': 'jason'}
4.传值的顺序(少传值与多传值)
forms组件中 定义的字段默认都是必须传值的 不能少传
少传了字段会报错
form_obj = views.MyForm({'username':'jason','password':'12345'})
form_obj.is_valid()
False
form_obj.errors
{'email': ['This field is required.']}
forms组件只会校验forms类中定义的字段 如果你多传了 不会有任何影响
多设置字段并不会影响
form_obj = views.MyForm({'username':'jason','password':'12345','email':'123@qq.com','xxx':'嘿嘿嘿'})
form_obj.is_valid()
True
2.2 渲染标签
第一步需要生成一个空的forms类的对象
class MyForm(forms.Form):
pass
def index(request):
第一步需要生成一个空的forms类的对象
form_obj = MyForm()
直接将生成的对象传递给前端页面
return render(request,'index.html',locals())
- froms组件只会帮你渲染获取用户输入的标签 不会帮你渲染提交按钮 需要你自己手动添加
第一种as_p as_ul as_table
直接将所有的信息一起渲染出来
reg.html
Copy<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<title>Title</title>
</head>
<body>
<div class="container">
<div class="row">
{#第一种渲染方式#}
<div class="col-md-offset-2 col-md-8">
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<hr>
{{ form.as_table }}
<hr>
{{ form.as_ul }}
<hr>
<input type="submit" value="提交" class="btn btn-success">
</form>
</div>
</div>
</div>
</body>
</html>
这种方式, Django的封装程度太高了, 我们完全不能够自定义样式, 所以它只能用来前期的页面快速搭建以及做测试使用. 最后的渲染结果巨丑无比... 实际基本不考虑它.
第二种
单独渲染每一个标签
<p>forms组件渲染标签方式2(不推荐使用,写起来太多)</p>
{#input框的提示信息 获取input框#}
{{ form_obj.username.label }}{{ form_obj.username }}
当我们使用form对象.字段名字的时候, 可以发现这样只渲染出单独的一个input框. 检查还能发现form组件渲染完毕后的一些规律.
第三种
上面这种方式也有一个不好的地方, 就是当字段多了以后, 每一个都需要添加类似的样式, 就比较麻烦, 这时候就需要用到第三种方式
遍历form对象来渲染出标签. 只需要对form对象作出以下小的变化, 就可以达到同样的效果
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>
{% endfor %}
可以定义类的label默认设置来渲染出页面的标签
class RegForm(forms.Form):
# 接下来的定义需要与模型表的字段类型一一对应
username = forms.CharField(
max_length=15, # 用户名最大长度为15
min_length=3, # 用户名的最小长度为3
label='用户名', # 渲染出在页面上的标签的名字
)
password = forms.CharField(
max_length=15, # 密码最大长度为15
min_length=3, # 密码的最小长度为3
label='密码', # 渲染出在页面上的标签的名字
)
2.3 展示信息
告诉浏览器不做前端校验 form表单设置novalidate
参数即可
<form action="" method="post" novalidate>
如何校验前端用户传入的数据
展示错误信息
views
def index(request):
# 获得空的forms类对象
form_obj = MyForm()
# 校验前端用户传入的数据
if request.method == 'POST':
# 获取用户的数据,在request.POST中,forms组件校验数据
form_obj = MyForm(request.POST) # 该变量名一定要与上面的变量名一致
if form_obj.is_valid():
print(form_obj.cleaned_data)
return HttpResponse('数据全部')
else:
print(form_obj.errors)
return render(request,'index.html',locals())
-------------------------------------------------------
index.html
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>
{{ form.label }}{{ form }}
{# form 等价于方式2中的对象点字段名(使用.0获取列表中的信心)#}
<span>{{ form.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit">
</form>
参数设置
class MyForm(forms.Form):
# username字段 最少三位,最多八位
username = forms.CharField(max_length=8,min_length=3,label='用户名',
error_messages={
'max_length':'用户名最长8位',
'min_length':'用户名最短3位',
'required':'用户名不能为空'
})
# email字段 必须是邮箱格式
email = forms.EmailField(label='邮箱',
error_messages={
'required':'邮箱不能为空',
'invalid':'邮箱格式错误'
})
-
label=
设置提示信息 -
error_messages={}
设置报错信息- required 不能为空
- invalid 邮箱格式
-
validations 内置校验器
RegexValidator 正则校验
2.4 校验数据补充
内置的校验器
内置的校验器
from django.core.validators import RegexValidator
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头'),
]
钩子函数 HOOK
会在普通校验全部符合后开始校验
上面只靠类型检查明显不符合一些比较复杂的校验, 例如用户名不能包含敏感词, 两次密码需要一致, 这都需要进行校验.
类内部的方法,是一个函数,函数体内你可以写任意的校验
局部钩子 clean_字段值
单独校验某一个字段的
.add_error
展示某一字段的错误信息
最后需返回字段数据return username
类中定义函数:
# 校验用户名中不能含有666
def clean_username(self):
# 校验通过的数据在 cleaned_data
username = self.cleaned_data.get('username')
# 第二层的判断
if '666' in username:
# 给username字段对应的框显示错误信息
self.add_error('username','后面的是报错')
# 将username数据返回
return username
全局钩子 clean
校验多个字段之间的关系的
return全局的数据return self.cleaned_data
类中
# 校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if not password == re_password:
self.add_error('re_password','两次密码不一致')
# 将全局的数据返回
return self.cleaned_data
补充知识点
小猿取经博客园密码
xiaoyuanqujing@666
其他字段及参数
-
lable 设置input对应的提示信息
-
initial 给input框设置默认值
-
required 默认为True,控制字段是否为空
-
widget 设置密码文本的显示方式
-
widget=forms.widgets.PasswordInput()
from django.forms import widgets widget=forms.widgets.PasswordInput()
-
widget=forms.widgets.TextInput()
括号内可以设置类内的属性 填写字典{},添加多个参数空格连接 widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jack'})
-
initial
初始值,input框里面的初始值。
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三" # 设置默认值
)
pwd = forms.CharField(min_length=6, label="密码")
error_messages
重写错误信息。
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密码")
password
class LoginForm(forms.Form):
...
pwd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
)
radioSelect
单radio值为字符串
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密码")
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
单选Select
class LoginForm(forms.Form):
...
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
多选Select
class LoginForm(forms.Form):
...
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
单选checkbox
class LoginForm(forms.Form):
...
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
多选checkbox
class LoginForm(forms.Form):
...
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
choice字段注意事项
在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。
方式一:
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
def __init__(self, *args, **kwargs):
super(MyForm,self).__init__(*args, **kwargs)
# self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')
方式二:
from django import forms
from django.forms import fields
from django.forms import models as form_model
class FInfo(forms.Form):
authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多选
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 单选