多对多三种创建方式
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
缺点:第三张表是自动创建的,无法扩展字段,扩展性差
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
3、半自动
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') """ 该表中可以有任意多的外键字段 可以扩展任意多字段 """
优点:可以任意的添加和修改第三张表中的字段
并且支持orm跨表查询
缺点:不支持内置的方法:add、remove、set、clear
Forms组件
form组件的作用:
1、生成页面可用的HTML标签 --> 渲染标签
2、对用户提交的数据进行校验 --> 校验数据
3、保留已输入的合法的内容 --> 展示信息
使用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()
校验数据
# 1.给写好的类 传字典数据(待校验的数据) form_obj = views.MyForm({'username':'jason','password':'12','email':'123'}) # 2.如何查看校验的数据是否合法 form_obj.is_valid() False # 只有当你的数据全部符合校验规则的情况下 结果才是True 否则都为False # 3.如何查看不符合规则的字段及错误的理由 form_obj.errors { 'password': ['Ensure this value has at least 3 characters (it has 2).'], 'email': ['Enter a valid email address.'] } # 4.如何查看符合校验规则的数据 form_obj.cleaned_data {'username': 'jason'} # 5.forms组件中 定义的字段默认都是必须传值的 不能少传 form_obj = views.MyForm({'username':'jason','password':'12345'}) form_obj.is_valid() False form_obj.errors{'email': ['This field is required.']} # 6.forms组件只会校验forms类中定义的字段 如果你多传了 不会有任何影响 form_obj =views.MyForm( {'username':'jason','password':'12345','email':'123@qq.com','xxx':'嘿嘿嘿'} ) form_obj.is_valid() True
渲染标签
forms组件只会帮你渲染获取用户输入的标签 不会帮你渲染提交按钮 需要你自己手动添加
渲染标签方式1:
封装程度态高 不推荐使用 但是可以用在本地测试
{{ form_obj.as_p }} <!--自动渲染所有input框 --> {{ form_obj.as_ul }} {{ form_obj.as_table }}
渲染标签方式2:
不推荐使用 写起来太烦了
{{ form_obj.username.label }}{{ form_obj.username }} {{ form_obj.username.label }}{{ form_obj.password }} {{ form_obj.username.label }}{{ form_obj.email }}
渲染标签方式3:推荐使用
{% for form in form_obj %} <p>{{ form.label }}{{ form }}</p> <!--form 等价于你方式2中的对象点字段名--> {% endfor %}
展示信息
<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>
注意:
数据的校验通常前后端都必须有
但是前端的校验可有可无 并且弱不禁风
后端的校验必须要有 并且必须非常的全面
如何告诉浏览器不做校验 form表单中加一个novalidate参数即可
<form action="" method="post" novalidate>
校验数据的方式:
内置校验器:
一般来说,你需要用到的正则匹配规则,在网上都能找到,不要重复造轮子
from django.core.validators import RegexValidator validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头'), ]
钩子函数:
当你觉得上面的所有的校验还不能够满足你的需求 你可以考虑使用钩子函数
钩子函数是一个函数 函数体内你可以写任意的校验代码
分为局部钩子和全局钩子。
局部钩子: 用于校验单个字段
# 校验用户名中不能含有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
补充知识:其他字段
label input对应的提示信息 initial input框默认值 required 默认为True控制字段是否必填 widget 给input框设置样式及属性 widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'}) widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2','username':'jason'})