多对多三种创建方式
全自动
ManyToManyField(to=)
- 优点: 无须自己创建多对多关系表, 支持orm跨表查询, 支持add, set, remove, clear方法
- 不足: 表的扩展性较差
class Book(models.Model): name = models.CharField(max_length=255) # 自动创建多对多关系表 authors = models.ManyToManyField(to='Author') class Author(models.Model): name = models.CharField(max_length=255)
纯手撸
- 优点: 字段完全由自己定义
- 不足: 不支持orm跨表查询, 不支持add, set, remove, clear方法
class Book(models.Model): name = models.CharField(max_length=255) class Author(models.Model): name = models.CharField(max_length=255) # 手动创建多对多关系表 class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateTimeField(auto_now=True)
半自动(推荐)
- 半自动其实是在手动创建和自动创建的基础上, 利用
ManyToManyField()
字段, 内部维护关系through='Book2Author'
该参数表示通过张表来建立表关系through_fields=('book', 'authors')
该参数表示通过括号内的两个字段维护关系, 以便支持orm跨表查询
- 优点: 可以任意添加和修改关系表中的字段, 支持orm跨表查询
- 不足: 不支持add, set, remove, clear方法
- 注意: 在哪一张表中创建多对多外键字段, 则through_fields传入的第一个参数就是该张表关联的字段
class Book(models.Model): name = models.CharField(max_length=255) # 半自动创建多对多关系表 authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'authors')) class Author(models.Model): name = models.CharField(max_length=255) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = models.DateTimeField(auto_now=True)
form组件
校验数据
- 导入:
from django import forms
- 自定义一个类 , 添加字段, 设置字段的限制条件
form_obj=MyForm(data)
传入一个待校验的字典数据, 实例化对象form_obj.is_valid()
校验传入的数据是否符合字段的限制条件form_obj.errors
返回一个字典, 存放不符合条件的字段以及错误信息forms.cleaned_data
返回一个字典, 存放符合条件的字段和对应的数据- 默认所有的字段都必须传值, 不能少传, 多传的会被忽略
from django import forms class MyForm(forms.Form): # 用户名的长度不能超过10字符, 不能少于3个字符 username = forms.CharField(max_length=10, min_length=3) # 密码位数不能小于六位 password = forms.CharField(min_length=6) # 邮箱需要符合有邮箱格式 email = forms.EmailField() # 在测试文件运行下面的代码 # 需要校验的数据 data = {'username': 'bigb', 'password': '12345', 'email': '123.com'} # 1.传入需要校验的数据, 实例化对象 form_obj = views.MyForm(data) # 2.is_valid() 判断数据是否符合条件 print(form_obj.is_valid()) # 3.errors 查看错误信息 print(form_obj.errors) ''' {'password': ['Ensure this value has at least 6 characters (it has 5).'], 'email': ['Enter a valid email address.']} ''' # 4.cleaned_data 查看符合条件的数据 print(form_obj.cleaned_data) # {'username': 'bigb'} # 5.少传数据 data = {'username': 'bigb', 'password': '123456'} form_obj = views.MyForm(data) form_obj.is_valid() Out[11]: False form_obj.errors Out[12]: {'email': ['This field is required.']}
渲染标签
- forms组件只会渲染输入标签, 不会渲染提交标签
{{ form_obj.as_p }}
{{form_obj.username.label}}
拿到username
字段的字段名(文本){{form_obj.username}}
拿到username
对应的input框{% for form in form_obj %} --- {{form.label}} {{form}}
- 给字段添加label参数, 可以自定义label的值, 默认是等于字段名
class MyForm(forms.Form): # 用户名的长度不能超过10字符, 不能少于3个字符 username = forms.CharField(max_length=10, min_length=3, label='用户名') # 密码位数不能小于六位 password = forms.CharField(min_length=6) # 邮箱需要符合有邮箱格式 email = forms.EmailField() def index(request): # 1.先生成一个空的form_obj form_obj = MyForm() # 2. 将form_obj发送到html文件 return render(request, 'index.html', locals())
<body> <h1>forms组件渲染标签</h1> {{ form_obj.as_p }} {{ form_obj.as_table}} {{ form_obj.as_ul}} <input type="submit"> </body> <body> <h1>forms组件渲染标签</h1> <p>{{ form_obj.username.label }} {{ form_obj.username }}</p> <p>{{ form_obj.password.label }} {{ form_obj.password }}</p> <p>{{ form_obj.email.label }} {{ form_obj.email }}</p> <input type="submit"> </body> <!--推荐使用--> <body> <h1>forms组件渲染标签</h1> {% for form in form_obj %} <p>{{ form.label }}{{ form }}</p> {% endfor %} <input type="submit"> </body>
展示错误信息
- 在form表单标签中加入属性 :
novalidation
来取消前端校验 {{form.errors}}
可以拿到校验后的错误信息, 是一个列表, 在前端渲染成ul
标签, 因此:{{form.errors.0}}
- 字段的
error_massages={}
参数用来自定义报错信息- required: 不能为空
- max_length: 最大长度
- min_length: 最小长度
- invalid: 格式错误
class MyForm(forms.Form): # 用户名的长度不能超过10字符, 不能少于3个字符 username = forms.CharField(max_length=10, min_length=3, label='用户名', error_messages={ 'required': '用户名不能为空', 'max_length': '长度不能超过10个字符', 'min_length': '长度不能小于3个字符' }) # 密码位数不能小于六位 password = forms.CharField(min_length=6, label='密码', error_messages={ 'required': '密码不能为空', 'min_length': '密码长度不能少于6位' }) # 邮箱需要符合有邮箱格式 email = forms.EmailField(label='邮箱', error_messages={ 'required': '邮箱不能为空', 'invalid': '邮箱格式错误' }) def index(request): # 1.先生成一个空的form_obj form_obj = MyForm() # 2. 将form_obj发送到html文件 if request.method == 'POST': form_obj = MyForm(request.POST) return render(request, 'index.html', locals())
<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>
validators校验器
Regexvalidator
:通过正则表达式完成数据的校验validators=[RegexValidator('正则表达式', '错误提示信息')]
phone = forms.CharField(label='手机号码', validators=[ RegexValidator(r'^(1[3-9])\d{9}$', '请输入正确的手机号码!')])
钩子函数
- 钩子函数是对数据的最后一道校验
- 在我们自定义的类下面创建
self.add_error('字段名', '错误信息')
给某个字段添加错误信息- 局部钩子函数返回校验字段
- 全局钩子函数返回
self.cleaned_data
# 局部钩子函数, 校验用户名中不能包含特殊字符 def clean_username(self): username = self.cleaned_data.get('username') forbidden_char = r'\'/!@#$%^&*()_+|}{":>?<' for i in forbidden_char: if i in username: self.add_error('username', '用户名中不能包含特殊符号!') return username # 函数名用到什么字段, 就返回什么字段 # 全局钩子函数, 校验密码和确认密码是否一致 def clean(self): confirm_password = self.cleaned_data.get('confirm_password') password = self.cleaned_data.get('password') if confirm_password != password: self.add_error('confirm_password', '密码输入不一致!') return self.cleaned_data # 函数名(全局)用到什么字段, 就返回什么字段
补充
initial
参数设置默认值required=Flase
设置该字段可为空label
参数设置input框对应的提示信息widget参数可以设置input标签的type参数和属性
widget=forms.widgets.PasswordInput()
widget=forms.widgetds.TextInput({'class': 'form-control c1 c2', 'username':'bigb})