多对多三种创建方式
全自动
class Book(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Authors') class Authors(models.Model): name = model.CharField(max_length=32)
好处:
orm自动创建第三张表
内置了四个操作第三张表的方法
- add
- remove
- set
- clear
坏处:
自动创建的第三张表无法修改字段,表的扩展性差
纯手撸
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等方法
半自动
推荐使用的创建方式
class Book(models.Model): title = models.CharField(max_length=32) authors = models.ManyToMany(to='Authors',through='Book2Author',throuth_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') # 该表中可以由任意多的外键字段 # 可以扩展任意的字段
好处:
可以任意的添加和修改第三张表中的字段,并且支持ORM跨表查询
坏处:
不支持add等方法
forms 校验性组件
form组件的常用字段
initial:初始值,input框里面的初始值 error_messages:重写错误信息 password:密文 radioselect:单radio值为字符串 label:input对应的提示信息 required:默认为True控制字段是否必填 widget:给input框设置样式及属性
form组件的主要功能:
- 生成页面可用的HTML标签
- 对用户提交的数据金进行校验
- 保留上次输入的内容
使用forms组件的前提需要导入forms模块
再写一个类:
class MyForm(forms.Form): username=forms.CharField(max_length=8,min_length=3) password = forms.Charfield(max_length=8,min_length=3) email = forms.EmailField()
校验数据
# 给写好的类传字典数据 form_obj = views.MyForm({'username':'qqq','password':'123','email':'123@qq.com'}) # 查看校验的数据是否合法 form_obj.is_valid() # 只有当数据全部符合校验规则,结果才是True # 查看不符合规则的字段以及错误的理由 form_obj.errors # 查看符合校验规则的数据 form_obj.cleaned_data
注意:forms组件中,定义的字段默认都是必须传值的,不能少传,但是多传不会有任何影响
渲染标签
forms组件只会渲染获取用户输入的标签,不会渲染提交按钮
forms组件渲染标签方式1:
{{form_obj.as_p}} <!--自动渲染所有input框--> {{form_obj.as_ul}} {{form_obj.as_table}}
封装程度太高,不推荐使用
forms组件渲染标签方式2:
{{ form_obj.username.label}}{{form_obj.username}} {{ form_obj.password.label}}{{form_obj.password}} {{ form_obj.email.label}}{{form_obj.email}}
写起来麻烦,不推荐使用
forms组件渲染标签方法3
{% for form in form_obj %} <p>{{ form.label }}{{ form}}</p> <!--form 等价于方式2中的对象.字段名--> {% endfor %}
展示信息
<p>forms组件渲染标签方式3:推荐使用 </p> <form action="" method="post" novalidate> {% for forms in form_obj %} <p> {{ forms.label }}{{ forms }} <span>{{ forms.errors.0 }}</span> </p> <!--form 等价于你方式2中的对象点字段名--> {% endfor %} <input type="submit"> </form>
内置的校验器
from django.core.validators import RegexValidator validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头'), ]
钩子函数
局部钩子
在form类中定义clean_字段名()
方法,实现对特定字段进行校验
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
全局钩子
在form类中定义clean()
方法,就能实现对字段进行全局校验
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