目录
表的多对多关系的三种创建方式
查阅框架文档及百度案例:
基于人家已经写好的功能修改
- 先看配置参数
- 前期就是猜, 改几个参数看结果, 看猜的是否对
- 整体修改
全自动创建
class Books(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Authors') class Authors(models.Model): name = models.CharField(max_length=32)
优点: 1. 不需要手动操作关系表, 全部由orm自动创建; 2. 并且内置了四个操作关系表的方法(add, remove, set, clear)
缺点: 自动创建的关系表无法扩展和修改字段
纯手撸(了解)
class Books(models.Model): title = models.CharField(max_length=32) class Authors(models.Model): name = models.CharField(max_length=32) class BooksToAuthors(models.Model): book = models.ForeignKey(to='Books') author = models.ForeignKey(to='Authors') create_time = models.DateField(auto_created=True) # 关系表中的扩展字段
优点: 关系表中的字段可以自己定义
缺点: 不再支持orm跨表查询以及四个操作关系表的方法(add, remove, set, clear)
半自动(推荐使用)
class Books(models.Model): title = models.CharField(max_length=32) ''' 1. 添加through和through_field参数, ManyToManyField就不会再自动创建关系表 2. through设置关系表通过自定义表建立, 3. through_fields设置通过自定义表中的哪两个字段建立多对多关系 4. 在哪张表中声明, 该表在自定义表中对应的字段就放在前面 ''' authors = models.ManyToManyField(to='Authors', through='BooksToAuthors', through_fields=('book', 'author')) class Authors(models.Model): name = models.CharField(max_length=32) # books = models.ManyToManyField(to='Books', through='BooksToAuthors', through_fields=('author', 'book')) class BooksToAuthors(models.Model): book = models.ForeignKey(to='Books') author = models.ForeignKey(to='Authors') create_time = models.DateField(auto_created=True) # 关系表中的扩展字段
优点: 可以添加和修改关系表中的字段, 并且支持跨表查询
缺点: 不支持四个操作关系表的方法(add, remove, clear, set)
forms组件简介
forms组件的作用
- 渲染标签--- 手动书写html代码获取用户输入
- 校验数据---将数据传递给后端做数据校验
- 展示信息---如果数据有错误, 展示错误信息
# 简易注册信息校验示例 def register(request): errors_dic = {'username': '', 'password': ''} if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if 'jinpingmei' in username: errors_dic['username'] = '不符合社会主义核心价值观' if len(password) <= 3: errors_dic['password'] = '密码不能少于4位' return render(request, 'register.html', locals()) ''' <form action="" method="post"> <p> username: <input type="text" name="username"> <span style="color: red;">{{ errors_dic.username }}</span> </p> <p> password: <input type="text" name="password"> <span style="color: red;">{{ errors_dic.password }}</span> </p> <input type="submit"> </form> '''
forms组件校验数据
使用forms组件, 先导入模块:
from django import forms
在views.py中自定义MyForm类
class MyForm(forms.Form): username = forms.CharField(max_length=8, min_length=3) # username字段最多8位, 最少3位 password = forms.CharField(max_length=8, min_length=3) email = forms.EmailField() # email字段必须是邮箱格式
测试代码的第二种方式: Python Console-->Django Console
from app01 import views form_obj = views.MyForm({'username': 'jason', 'password': '12', 'email': '456'}) # 实例化时参数为字典形式 form_obj.is_valid() # False, 所有数据全部符合校验规则才为True form_obj.errors # {'password': ..., 'email': ['Enter a valid email address.']}, 查看不符合规则的字段及错误信息 form_obj.cleaned_data # {'username': 'jason'}, 查看符合校验规则的数据 ''' 1. forms组件的类中定义的字段默认都必须传值, 不能少传 2. forms组件只会校验类中定义的字段, 如果传入其他字段, 不会有任何影响 '''
forms组件渲染标签
forms组件只会渲染获取用户输入的标签, 不会渲染提交按钮
def index(request): # 渲染标签, 需先生成一个空的MyForm类的对象 form_obj = MyForm() return render(request, 'index.html', locals())
forms组件渲染标签方式一
封装程度高, 难扩展, 只用于本地测试
''' {{ form_obj.as_p }} # 会自动渲染input框和label标签, 由p标签包裹 {{ form_obj.as_ul }} # ..., 由ul标签包裹 {{ form_obj.as_table }} # ..., 渲染到一行上 '''
forms组件渲染标签方式二
组合: form_field_obj为form_obj的属性
class MyForm(forms.Form): username = forms.CharField(max_length=8, min_length=3, label='用户名') password = forms.CharField(max_length=8, min_length=3, label='密码') email = forms.EmailField(label='邮箱') ''' {% for form_field_obj in form_obj %} <p>{{ form_field_obj.label }}{{ form_field_obj }}</p> {% endfor %} '''
form组件展示信息
数据的校验通常情况前后端都有, 但前端的校验弱不禁风, 所以后端的校验必须要有, 且需非常全面
浏览器识别到使用forms组件时会自动使用前端的校验功能
def index(request): # 渲染标签, 需先生成一个空的MyForm类的对象 form_obj = MyForm() if request.method == 'POST': # 前端识别到后端使用forms组件时会自动先进行一轮校验 form_obj = MyForm(request.POST) if form_obj.is_valid(): return HttpResponse('数据全部OK') else: print(form_obj.errors) return render(request, 'index.html', locals())
设置前端不做校验: <form action="" method="post" novalidate>
def index(request): # 渲染标签, 需先生成一个空的MyForm类的对象 form_obj = MyForm() # 空对象渲染输入框 if request.method == 'POST': form_obj = MyForm(request.POST) # form_obj实际渲染用户数据, 两个对象的名称需一致 if form_obj.is_valid(): return HttpResponse('数据全部OK') return render(request, 'index.html', locals()) ''' <form action="" method="post" novalidate> {% for form_field_obj in form_obj %} <p> {{ form_field_obj.label }}{{ form_field_obj }} # label默认获取到的是类中字段名的首字母大写形式 <span>{{ form_field_obj.errors.0}}</span> # 前端获取报错信息固定写法 </p> {% endfor %} <input type="submit"> </form> ''' class MyForm(forms.Form): username = forms.CharField( max_length=8, min_length=3, label='用户名', error_messages={ # 自定义显示报错信息 'max_length': '用户名最长八位', 'min_length': '用户名最短3位', 'required': '用户名不能为空' } ) ... email = forms.EmailField( label='邮箱', error_messages={ 'required': '邮箱不能为空', 'invalid': '邮箱格式错误' } )
forms组件自定义校验
正则校验
''' from django.core.validators import RegexValidator class MyForm(forms.Form): username = forms.CharField( ... ... validators=[ RegexValidator(r'[0-9]+$', '请输入数字!'), # 第一个参数为正则表达式, 第二个参数为校验不通过时的报错信息 RegexValidator(r'^159[0-9]+$', '数字必须以159开头!'), ] ) '''
钩子函数
书写代码校验字段输入是否合法, 在其他校验合法之后再进行钩子函数代码校验
局部钩子: 校验单个字段
''' class MyForm(forms.Form): ... # 校验用户名中不能含有666 def clean_username(self): username = self.cleaned_data.get('username') if '666' in username: self.add_error('username', '光喊666是不行的') return username '''
全局钩子: 校验多个字段
''' class MyForm(forms.Form): ... # 校验两次输入密码是否一致 def clean(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if not confirm_password == password: self.add_error('confirm_password', '两次密码不一致!') return self.cleaned_data '''
其他字段及参数
需要掌握
''' class MyForm(forms.Form): username = forms.CharField( ..., label='用户名', # input框对应的提示信息 initial='jason', # 初始值 required=False, # 允许字段值为空 widget=forms.widgets.PasswordInput(attrs={'class': 'form-control c1', 'pwd': '123'}), # 密文展示, 给input框设置样式及属性 ... ) # 前端对应标签: <input type="password" ... class="form-control c1" pwd="123" ...> '''
了解, 会copy即可
''' radioSelect: gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", initial=3, widget=forms.widgets.RadioSelect() ) 单选Select下拉框 hobby = forms.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=3, widget=forms.widgets.Select() 多选Select框, 无需下拉 hobby = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple() ) 单选checkbox keep = forms.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput() ) 多选checkbox hobby = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() ) '''
来源:https://www.cnblogs.com/-406454833/p/12011928.html