多对多的三种创建方式

1.全自动(就是平常我们创建表多对多关系的方式)

class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
authors = models.ManyToManyField(to='Author') class Author(models.Model):
name = models.CharField(max_length=32)
优势:不需要你手动创建第三张表
不足:由于第三张表不是你手动创建的,也就意味着第三张表字段是固定的无法做扩展

2.纯手动(手动建关系表)

class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2) class Author(models.Model):
name = models.CharField(max_length=32) class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
create_time = models.DateField(auto_now_add=True)
优势:第三张可以任意的扩展字段
不足:orm查询不方便

3.半自动(推荐使用)

class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author'))
# through 告诉django orm 书籍表和作者表的多对多关系是通过Book2Author来记录的
# through_fields 告诉django orm记录关系时用过Book2Author表中的book字段和author字段来记录的
"""
多对多字段的
add
set
remove
clear不支持
""" class Author(models.Model):
name = models.CharField(max_length=32)
# books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author', 'book')) #手动创建的第三张表
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
create_time = models.DateField(auto_now_add=True)
优点:即不用自己创建第三张表了,也可以任意扩展字段了
缺点:这种多对多关系中不能使用add/set/remove/clear这些方法了

form组件

一、什么是form组件,可以干什么

1.forms组件就是一个类,可以检测前端传来的数据,是否合法。
例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 >>>校验数据
2.还可以前端页面搭建 >>> 渲染页面
3.展示错误信息 >>> 渲染错误信息

二、form组件的使用

1.使用语法

from django.shortcuts import render, HttpResponse
from django import forms #1.先写一个类,继承Form
class MyForm(forms.Form):
#定义属性,用来校验
#限制最大长度为8,最小长度为3
name = forms.CharField(max_length=8,min_length=3)
pwd = forms.CharField(max_length=8,min_length=3)
#校验邮箱
email = forms.EmailField() #2.在视图函数中使用MyForm来校验数据
#实例化产生对象,将需要校验的数据传入(可以传字典,可以不传),这个数据是前端传递过来的数据
myform = MyForm(request.POST) #3.校验,is_valid如果是true表示校验成功(满足myform里面的所有条件),反之,验证失败
if myform.is_valid():
print(myform.cleaned_data) #打印校验通过的数据
return HttpResponse('校验成功') else:
#校验失败的信息 是一个字典,它是所有错误信息 {错误字段名:[错误原因]}
print(myform.errors) #errors是一个列表,表示每个字段的错误信息
return HttpResponse('校验失败')

方法总结:

clean_data  验证通过的数据
errors 错误数据的对象
errors.as_data 错误数据的信息

注意事项

1.自定义的类中所有的字段默认都是必须要传值的
2.可以额外传入类中没有定义的字段名,forms组件不会去校验,也就是多传没有关系
3.实例化时,传入必须是字典,也可以不传
form_obj = views.LoginForm({'username':'jason','password':'','email':'123@qq.com'})
form_obj.is_valid()
True form_obj = views.LoginForm({'username':'jason','password':''})
form_obj.is_valid()
False form_obj = views.LoginForm({'username':'jason','password':'','email':'123@qq.com','hobby':'read'})
form_obj.is_valid()
True

2.组件的参数及其他操作方式

max_length   #代表该字段最长可以为多少
min_length #代表该字段最短可以为多少
error_messages #设置错误信息的属性
required #默认值为True,意思是你前端传来的字段必须有它,没有的话校验失败
label #注释信息label ='用户名' 在前端渲染可以直接对象.label获取值
initial #设置默认值

widget #控制标签属性和样式
widget = widgets.PasswordInput() #你在模板渲染的时候,就会渲染成Input框,password样式
控制标签属性
widget = widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})

#例子
pwd = forms.CharField(max_length=8,min_length=3,required=True,label='密码',
error_messages = {'max_length':'最长是8','min_length':'最短是3','required':'这个必须填'}
)
其他操作方式
# 单选的radio框
gender = forms.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框
hobby1 = 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
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)

三、渲染页面、渲染错误信息

#form组件可以在视图函数中使用,也可以在模板中使用
#视图层
def reg(request):
myform = MyForm()
   if request.method == 'POST':
   myform = MyForm(request.POST)
     print(request.POST) #<QueryDict: {'name': ['小张'], 'pwd': ['123123'], 'email': ['119@qq.com']}> return render(request,'reg.html',locals()) #把myform对象传到前端页面了
#模板层
#第一种渲染方式(封装程度太高,一般只用于本地测试,通常不适用)
<form action='' method='post'>
{{ myform.as_p }}
{{ myform.as_ul }}
{{ myform.as_table}}
<input type='submit' value = '提交'></input>
</form> #第二种渲染页面的方式(可扩展性高,书写麻烦)
<form action='' method='post'>
{{myform.name.label}}:{{myform:name}}
{{myform.pwd.label}}:{{myform:pwd}}
{{myform.email.label}}:{{myform:email}}
<input type='submit' value = '提交'></input>
</form> #第三种渲染方式(推荐)
<form action='' method='post'>
{% for foo in myform %}
<p> {{ foo.lable }} : {{ foo }}
<span>{{ foo.errors.0 }}</span> //注意后面加0 错误信息
</p>
<input type='submit' value = '提交'></input>
</form>

注意事项:

1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入的标签  提交按钮需要你手动添加
2.input框的label注释 不指定的情况下 默认用的类中字段的首字母大写

 四、钩子函数(HOOK)

forms组件暴露给用户,可以自定义的校验规则    用法:在自定义的form类中定义一个函数即可

1.局部钩子(针对某一个字段做额外的校验) 

名字叫:clean_字段名,内部,取出该字段进行校验,如果通过,将该字段返回,如果失败,抛异常

#函数名:clean_字段名字
def clean_name(self): #self是当前form对象
name = self.cleaned_data.get('name') #从验证通过的数据中再次筛选
if '' in username:
#失败,抛异常,把异常信息以('key','value')形式写入add_error中
self.add_error('name','不能包含666')
#正常,把name返回到clean_data,将name写入clean_data字典中
return name

注意点:

  • 这些函数是写在自定义类form里面的,需要校验哪个字段就以 clean_字段名写一个校验函数
  • 校验失败,通过add_error('字段名','错误信息'),以{key:value}形式写入到errors字典中
  • 校验成功,返回name到clean_data,写入clean_data字典中

2.全局钩子(针对多个字段做额外的校验)

#重写clean方法
def clean(self):
#能走到这步,说明前面的校验已经通过了,下面校验两次两次密码是否输入一致
pwd = self.clean_data.get('pwd')
re_pwd = self.clean_data.get('re_pwd')
if pwd == re_pwd:
#校验成功,直接返回clean_data
return self.clean_data
else:
#校验失败,把错误信息放入errors中
self.add_error('re_pwd','两次密码输入不一致')
或者
#抛出异常
raise ValidationError('两次密码不一致')

注意点:

  • 校验失败,有两种写法,抛异常,将异常信息以{'__all__':[value,]}写入errors字典中
  • 校验成功,返回clean_data字典
  • 抛出异常类型为 ValidationError, from django.core.exceptions import ValidationError导入

钩子错误信息渲染注意点:

  • 局部钩子抛出的异常会添加到该字段中的错误信息中,获取错误信息

   前端: for循环对象  {{ foo.errors.0}}

  • 全局钩子抛出的异常会添加到__all__中,获取错误信息:

  后端: myform.errors.get('__all__')[0]   注意先判断myform.errors.get('__all__')是否存在

    前端:{{ myform.errors.__all__.0}}

  • 能走到这些函数,说明前面的form组件的那些校验都成功了,此时就可以从clean_data中取数据,因为此时clean_data中的数据全部符合,都找的到,而且clean_data是字典比较好取值。

 五、完整的form组件校验

 1.视图层

from django.shortcuts import render, HttpResponse, redirect

# forms组件数据校验的功能
# 第一步:先要继承Form
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError # 写一个类
class MyForm(forms.Form):
# 定义一个属性,可以用来校验字符串类型
# 限制最大长度是8,最小长度是3
name = forms.CharField(max_length=8, min_length=3, label='用户名'
error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.TextInput(attrs={'class': 'form-control'})) pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密码',
error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.PasswordInput()) re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='确认密码',
error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.PasswordInput())
# 校验是否是邮箱格式
email = forms.EmailField(label='邮箱', error_messages={'required': '这个必须填', 'invalid': '不符合邮箱格式'}) # aa = forms.CharField(label='选择', error_messages={'required': '这个必须填', 'invalid': '不符合邮箱格式'},widget=widgets.CheckboxInput())
def clean_name(self):
# self:当前form对象
name = self.cleaned_data.get('name')
if name.startswith('sb'):
# 失败,抛异常
raise ValidationError('不能以傻逼开头')
# 正常,把name返回
return name def clean(self):
pwd = self.cleaned_data.get('pwd')
re_pwd = self.cleaned_data.get('re_pwd')
if pwd == re_pwd:
return self.cleaned_data
else:
raise ValidationError('两次密码不一致') def index_form(request):
# 生成对象时(实例化),需要传入要校验的数据(字典)
if request.method == 'GET':
myform = MyForm()
return render(request,'indxe2.html',locals())
elif request.method == 'POST':
myform = MyForm(request.POST)
if myform.is_valid():
# print(myform.cleaned_data) # 验证通过的数据
# models.User.objects.create(name='lqz',pwd='123',re_pwd='123)
myform.cleaned_data.pop('re_pwd')
models.User.objects.create(**myform.cleaned_data)
return redirect('http://www.baidu.com')
else:
all_error = myform.errors.get('__all__')
if all_error:
all_error = all_error[0]
# print(myform.errors.as_data) return render(request, 'indxe3.html', locals())

2.模板层

<form action="" method="post" novalidate>
{% for foo in myform %}
<p>{{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span></p>
{% endfor %} <input type="submit" value="提交"><span>{{ all_error }}</span>
</form>

Django框架(十)--ORM多对多关联关系三种创建方式、form组件的更多相关文章

  1. django----多对多三种创建方式 form组件

    目录 多对多三种创建方式 全自动 全手动 半自动 form组件 基本使用 form_obj 及 is_valid() 前端渲染方式 取消前端自动校验 正则校验 钩子函数(Hook方法) cleaned ...

  2. 2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

    摘要 MTV与MVC 多对多表三种创建方式 ajax ,前后端传输数据编码格式contentType 批量插入数据和自定义分页器 一.MVC与MTV MVC(Model View Controller ...

  3. 多对多的三种创建方式-forms相关组件-钩子函数-cookie与session

    多对多的三种创建方式 1.全自动(推荐使用的**) 优势:第三张可以任意的扩展字段 缺点:ORM查询不方便,如果后续字段增加更改时不便添加修改 manyToManyField创建的第三张表属于虚拟的, ...

  4. ORM中choices参数(重要)、MTV于MVC模型、多对多关系三种创建方式

    choices参数(重要) **使用方式

  5. Django-多对多关系的三种创建方式-forms组件使用-cookie与session-08

    目录 表模型类多对多关系的三种创建方式 django forms 组件 登录功能手写推理过程 整段代码可以放过来 forms 组件使用 forms 后端定义规则并校验结果 forms 前端渲染标签组件 ...

  6. Django多对多表的三种创建方式,MTV与MVC概念

    MTV与MVC MTV模型(django): M:模型层(models.py) T:templates V:views MVC模型: M:模型层(models.py) V:视图层(views.py) ...

  7. 多对多三种创建方式、forms组件、cookies与session

    多对多三种创建方式.forms组件.cookies与session 一.多对多三种创建方式 1.全自动 # 优势:不需要你手动创建第三张表 # 不足:由于第三张表不是你手动创建的,也就意味着第三张表字 ...

  8. Struts2之命名空间与Action的三种创建方式

    看到上面的标题,相信大家已经知道我们接下来要探讨的知识了,一共两点:1.package命名空间设置:2.三种Action的创建方式.下面我们开始本篇的内容: 首先我们聊一聊命名空间的知识,namesp ...

  9. JavaScript 闭包的详细分享(三种创建方式)(附小实例)

    JavaScript闭包的详细理解 一.原理:闭包函数--指有权访问私有函数里面的变量和对象还有方法等:通俗的讲就是突破私有函数的作用域,让函数外面能够使用函数里面的变量及方法. 1.第一种创建方式 ...

随机推荐

  1. swoolefy PHP的异步、并行、高性能网络通信引擎内置了Http/WebSocket服务器端/客户端

    近半年来努力付出,项目终于要正式结项了,团队4人经历了很多困难,加班加点,最终完成了!剩下的时间将总结一下在该项目中用到知识和遇到问题.今天就从swoole说起!项目中实现异步大文件传输的功能,在服务 ...

  2. A@GC*014

    A@GC*014 A Cookie Exchanges 卡时跑了1s就输出-1 每次操作会使三个数的极差缩小一半,所以最多\(\log\)次之后就会出现\(A=B=C\)的情况,可以直接判掉 B Un ...

  3. A~G)C004

    AGC004 A Divide a Cuboi 我不会,谁能教教我/kk https://agc004.contest.atcoder.jp/submissions/7919351 B Colorfu ...

  4. Linux apache自建证书搭建https

    前言          搭建https有两种方式,分为单向认证和双向认证.单向认证就是传输的数据加密过了,但是不会校验客户端的来源,也就只有客户端验证服务端证书.   单向认证 1.安装mod_ssl ...

  5. Struts2工作原理和核心文件

    一.Struts2工作原理 如下图: 二.Struts2配置文件 1.web.xml 任何MVC框架都需要与Web应用整合,这就不得不借助于web.xml文件,只有配置了web.xml文件的Servl ...

  6. Vintage_坏客户定义

    python信用评分卡建模(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_ca ...

  7. spring boot允许跨域(CORS)的配置

    添加@Configuration配置类即可. @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { ...

  8. sessionid 特性

    本文为博主原创,转载请注明出处: sessionid 是服务器用来辨别客户端浏览器身份的号码,就像人的身份证一样.当用户第一次访问网站时,服务器会分配一个独一无二的 sessionid 给用户浏览器: ...

  9. sumdoc t3 final dir.txt

    C:\Users\zhoufeiyue\Documents\sumdoc t3 final\sumdoc t3 final dir.txtC:\Users\zhoufeiyue\Documents\s ...

  10. js---if判断的几种写法

    在写JS中最常见的就是 if 判断,但是直接写 if(){}else{}; 太low ,下面是常见的几种js的if判断的写法: /** * js 判断的几种写法 */ var a = 10,b = 2 ...