Django(九)
Django(九)---多对多的创建方式,form组件
多对多表创建方式
全自动
通过Django中的orm,只要定义好表类,orm就对自动创建多对多的表关系,自动建立第三张表,并且还可以通过add
remove
set
clear
对第三张表进行操作
缺点:
因为第三张表是自动创建的,所以该表无法扩展和自定义字段,标的扩展性较差
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的跨表查询,也没有正反查询的概念
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)
半自动
在全自动的基础上,手动创建第三张表,并在MangyToManyField方法内再加一些参数(through='手动创建的第三张表名',through_fields=('外键字段1','外键字段2')
'外键字段1'当前所在表的外键
'外键字段2'关联表的外键
通过该方式创建第三张表,可以自定义添加任意字段,并且支持orm查询
缺点:
不支持 add
remove
set
clear
方法,对第三张表进行操作
class Book(models.Model):
title = models.CharField(max_length=32)
# 多对多关系字段
authors = models.ManyToManyField(to='Authors',through='Book2Author',through_fields=("book","authors"))
"""
当你的ManyToManyField只有一个参数to的情况下 orm会自动帮你创建第三张表
如果你加了through和through_fields那么orm就不会自动帮你创建第三张表 但是它会在内部帮你维护关系 让你能够继续使用orm的跨表查询
through 自己指定第三张关系表
through_fields 自己指定第三张关系表中 到底哪两个字段维护者表与表之间的多对多关系
"""
class Authors(models.Model):
name = models.CharField(max_length=32)
# 多对多关系字段 等价
books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=("authors","book"))
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
authors = models.ForeignKey(to='Authors')
# 该表中可以由任意多的外键字段
# 可以扩展任意的字段
form组件
通过form组件,对用户输入的信息进行校验
如:
- 用户名规定不能含有敏感词
- 密码不能少于3位
def register(request):
errors = {'username':'','password':''}
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())
<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">
<p></p>
</form>
校验数据
使用form组件时,需要提前定义一个类
from django import forms
class MyForm(forms.Form):
username = forms.CharField(max_length=8,min_length=3)
# 使用CharField字段,max_length表示最多位数,min_length表示最少位数
password = forms.IntegerField(max_value=8,min_value=3)
# email字段 必须是邮箱格式
email = forms.EmailField()
通过 form_obj.is_valid()
方法,可以校验提交的数据是否符合条件
只有当数据全部符合校验规则的情况下,结果才是True
通过 form_obj.errors
方法,可以获取不符合规则的字段及错误的理由
通过 form_obj.cleaned
方法,可以获取校验通过的数据,返回的是一个字典
forms组件中定义的字段默认都是必须传值的,不能少传,如果少传会报错
forms组件只会校验forms类中定义的字段,如果多传了,不会有任何影响
渲染标签
<p>方式一:速度快,但是封装成程度太高,不能加标签样式</p>
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
<p>方式二:</p> #方式二写法过于繁琐
{{ form_obj.username.label }}{{ form_obj.username }}
{{ form_obj.password.label }}{{ form_obj.password }}
{{ form_obj.email.label }}{{ form_obj.email }}
<p>方式三:</p> #使用该方法,不管有多少个输入框,都可以通过for循环一次性渲染
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>#和方式2中的对象点字段名一样
{% endfor %}
通过在自定义的MyForm
中的属性值设置label
的值,可以自定义前端label的是值
通过设置widget=forms.widgets.TextInput({'class':'form-control',键值对})
的值,可以对标签进行js渲染
展示信息
使用form组件,前端会自动识别,并帮你做校验
但是前端的校验保护措施过于薄弱,因此在写项目时,需要取消前端的校验
在后端进行真正的校验
让浏览器不做校验,需要在form表单中添加一个novalidate
参数
<form action="" method="post" novalidate>
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>{{ form.label }}{{ form }} <span>{{ form.errors.0 }}</span></p>
{% endfor %}
<input type="submit">
</form>
通过{{ form.errors.0 }}
可以获取后端传过来的报错信息,报错信息为英文
在后端自定义的MyForm
类中,给属性值自定义error_messages
值,可是是前端得到自定义的报错信息
username = forms.CharField(max_length=8,min_length=3,label='用户名',initial='默认值',
error_messages={
'max_length':'用户名最长八位',
'min_length':'用户名最短三位',
'required':'用户名不能为空'
},required=False,
widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'})
)
内置的校验器
通过validators
设置校验规则,规则一般为正则表达式
from django.core.validators import RegexValidator
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头'),
]
勾子函数
符合所有字段规则的数据,才会进行勾子函数内的校验
form组件校验通过的数据会存放在cleaned_data中
局部钩子
# 校验用户名中不能含有666 局部钩子
def clean_username(self):
username = self.cleaned_data.get('username')
if '666' in username:
# 给username所对应的框展示错误信息
# self.add_error('username','光喊666是不行的')
raise ValidationError('到底对不对啊')
# 将username数据返回
return username
全局钩子
# 校验密码 确认密码是否一致 全局钩子
def clean(self):
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password")
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
# 将全局的数据返回
return self.cleaned_data
补充知识点
在自定义类的实行中设置 initial
值,会在前端中显示初始值
设置required
属性,默认为True,为True时该输入框不能为空,设置为False,可以为空
label input对应的提示信息
initial input框默认值
required 默认为True控制字段是否必填
widget 给input框设置样式及属性
widget=forms.widgets.PasswordInput({'class':'form-control c1 c2',})
widget=forms.widgets.TextInput({'class':'form-control c1 c2',})
widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2',})