今日内容:
1.多对多三种创建方式

2.forms组件

3.钩子函数

4.forms组件其他字段及操作方式

5.cookie和session

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)

第二种:纯手动(这种了解就可以了)

自己创建第三张表。
优势:第三张可以任意的扩展字段
不足:orm查询不方便,因为正向查询的时候是依靠字段的,这个时候俩边都没有字段。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)

第三种:半自动(这种也是推荐使用的)

优势:结合了全自动和纯手动的俩个优点
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字段来记录的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不支持

2.forms组件:

再讲forms组件之前先写一个小列子:

自己手动实现一个注册功能
当用户的用户名包金萍梅   提示不符合社会主义核心价值观
当用户的密码短于三位      提示密码太短了,不符合要求

前端:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <form action="" method="post">
 9     <p>username:
10         <input type="text" name="username">
11 {#        在输入框后面用一个span标签占位如果有敏感词汇就会显示,#}
12         <span style="color: red;">{{ errors.username }} </span>
13     </p>
14     <p>password:
15         <input type="password" name="password">
16         <span style="color: darkorange">{{ errors.password }}</span>
17     </p>
18     <input type="submit">
19 </form>
20
21
22 </body>
23 </html>

View Code

后端:

 1 def login(request):
 2     errors = {'username':'','password':''}
 3     if request.method == 'POST':
 4         username = request.POST.get('username')
 5         password = request.POST.get('password')
 6         if '金萍梅' in username:
 7             # 如果输入框里面有敏感词汇,就把username赋上值
 8             errors['username'] = '不符合社会主义核心价值观'
 9         if len(password) < 3:
10             errors['password'] = '密码小于三位,不安全'
11     return render(request,'login.html',locals())

View Code

上面的这个小列子用到了
1.前端页面的搭建  >>>  渲染页面
2.将数据传输到后端做校验  >>>  校验数据
3.展示错误信息   >>> 展示信息

接下来正式进入forms组件的学习:

forms组件能够直接帮你完成上面的三个步骤:1.渲染前端页面2.校验数据是否合法3.展示错误信息

1.forms组件的基本用法:

首先在views里面写一个继承了forms.Form的类from django import formsclass LoginForm(forms.Form):username = forms.CharField(max_length=8,min_length=3)  # 用户名最长八位最短三位password = forms.CharField(max_length=8,min_length=5)  # 密码最长八位最短五位email = forms.EmailField()  # email必须是邮箱格式

注意:在models里面这个字段是没有限制效果的,但是在这里就会有限制效果。

2.基本使用:(需要在这里面使用)

        from app01 import views1.将需要校验的数据 以字典的方式传递给自定义的类 实例化产生对象form_obj = views.LoginForm({'username':'jason','password':'123','email':'123'})2.如何查看数据是否全部合法form_obj.is_valid()  # 只有所有的数据都符合要求 才会是True
                False3.如何查看错误原因form_obj.errors{'password': ['Ensure this value has at least 5 characters (it has 3).'], 'email': ['Enter a valid email address.']}4.如何查看通过校验的数据form_obj.cleaned_data  {'username': 'jason'}总结:
查看数据是否全部合法:form_obj.is_valid()
查看错误原因:form_obj.errors
查看通过校验的数据:form_obj.cleaned_data  

这里有一些需要注意的事项:

1.自定义类中所有的字段默认都是必须要传值的
2.可以额外传入类中没有定义的字段名 forms组件不会去校验,也就意味着多传一点关系也没有代码验证:

 1             form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com'})
 2                 form_obj.is_valid()
 3                 True
 4
 5                 form_obj = views.LoginForm({'username':'jason','password':'123456'})
 6                 form_obj.is_valid()
 7                 False
 8
 9                 form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com','hobby':'read'})
10                 form_obj.is_valid()
11                 True

View Code

重点:

forms渲染页面的三种方式:
前端:

<p>第一种渲染页面的方式(但是这种方式封装程度太高,一般只用于本地测试,通常不适用)</p>
{{ form_obj.as_p }}  {# 套p标签写后端传过来的字段进行渲染 #}
{{ form_obj.as_ul }}  {# 套ul标签写后端传过来的字段进行渲染#}
{{ form_obj.as_table }} {# 套table标签写后端传过来的字段进行渲染 #}<p>第二种渲染页面的方式(.label拿到的是字段名首字母大写,可扩展性高,但是书写麻烦)</p>
<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><p>第三种渲染页面的方式(这个是推荐使用的)</p>
{% for foo in form_obj %}<p>{{ foo.label }}:{{ foo }}</p>
{% endfor %}

后端:

from django import forms

class LoginForm(forms.Form):    username = forms.CharField(max_length=8,min_length=3,label='用户名') # 意思就是用户名最长8位,最短3位    password = forms.CharField(max_length=8,min_length=5,label='密码') # 意思就是密码最长8位,最短5位    email = forms.EmailField(label='邮箱') # email必须是邮箱格式
ps:指定一下label是为了前端字段显示为中文def reg(request):# 1.生成一个空的自定义类的对象form_obj = LoginForm()# 2.将该对象传递给前端页面return render(request,'reg.html',locals())

总结:(渲染页面需要注意的事项)

1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入的标签  提交按钮需要你手动添加
2.input框的label注释  不指定的情况下 默认用的类中字段的首字母大写
注意:校验数据的时候可以前后端都校验 做一个双重的校验但是前端的校验可有可无 而后端的校验则必须要有,因为前端的校验可以通过爬虫直接避开前端取消浏览器校验功能form标签指定novalidate属性即可<form action="" method='post' novalidate></form>

forms组件展示错误信息:

几个重要的参数:

把前端报错的英文改为中文:
关键字:error_messages = {'max_length': '用户名最大八位','min_length': '用户名最小三位','required': '用户名不能为空'}让前端输入的input框中可以为空:
required=False也支持正则表达式

前端:

<form action="" method="post" novalidate><p>第三种渲染页面的方式(这个是推荐使用的)</p>
{% for foo in form_obj %}<p>{{ foo.label }}:{{ foo }}{# 因为foo就是一个队像,所以可以点里面的属性,因为我只想要文本值不想要他帮我渲染所以点个0 #}<span>{{ foo.errors.0 }}</span></p>
{% endfor %}<input type="submit">
</form>

后端:

 1 from django import forms
 2 from django.core.validators import RegexValidator
 3
 4 class LoginForm(forms.Form):
 5     username = forms.CharField(max_length=8,min_length=3,label='用户名',
 6                                error_messages = {
 7                                    'max_length': '用户名最大八位',
 8                                    'min_length': '用户名最小三位',
 9                                    'required': '用户名不能为空'
10                                }
11                                ) # 意思就是用户名最长8位,最短3位
12     password = forms.CharField(max_length=8,min_length=5,label='密码',
13                                 error_messages = {
14                                     'max_length': '密码最大八位',
15                                     'min_length': '密码最小三位',
16                                     'required': '密码不能为空'
17                                 },required=False,
18                                ) # 意思就是密码最长8位,最短5位
19     email = forms.EmailField(label='邮箱',
20                              error_messages={
21                                  'required':'邮箱不能为空',
22                                  'invalid':'邮箱格式不正确'
23                              }
24                              ) # email必须是邮箱格式
25     # 也支持使用正则表达式
26     phone = forms.CharField(
27         validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
28     )
29 def reg(request):
30     # 1.生成一个空的自定义类的对象
31     form_obj = LoginForm()
32     if request.method == 'POST':
33         # 3.获取前端post请求提交过来的数据
34         # 那么由于request.POST其实也是一个字典,所有可以直接传给LoginForm
35         form_obj = LoginForm(request.POST)
36         # 4.校验数据,让from组件帮你去校验
37         if form_obj.is_valid():
38             # 5.如果数据全部通过,应该写入数据库,这里就不写了
39             pass
40         # 6. 如果不通过,就像前端展示错误信息
41     return render(request,'reg.html',locals())

View Code

钩子函数(HOOK)

forms组件暴露给用户,可以自定义的校验规则

1.局部钩子:

  # 因为这是方法,直接写在类中# 局部钩子(针对某一个字段做额外的校验)比如说校验用户名中不能包含666,包含就提示def clean_username(self):username = self.cleaned_data.get('username')if '666' in username:self.add_error('username','用户名中不能包含666')return username

2.全局钩子

  # 全局钩子(针对多个字段做额外的校验)比如说校验用户俩次密码是否一致def clean(self):password = self.cleaned_data.get('password')confirm_password = self.cleaned_data.get('confirm_password')if password !=confirm_password:self.add_error('confirm_password','俩次密码不一致')return self.cleaned_data

4.forms组件其他字段及操作方式:

required  是否必填label         注释信息error_messages  报错信息initial        默认值widget        控制标签属性和样式widget=widgets.PasswordInput()控制标签属性widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})

其他字段了解知识点(知道有这些对象 需要用到的时候 能够知道去哪找)

 1 # 单选的radio框
 2             gender = forms.ChoiceField(
 3                 choices=((1, "男"), (2, "女"), (3, "保密")),
 4                 label="性别",
 5                 initial=3,
 6                 widget=forms.widgets.RadioSelect()
 7             )
 8             # 单选select
 9             hobby = forms.ChoiceField(
10                 choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
11                 label="爱好",
12                 initial=3,
13                 widget=forms.widgets.Select()
14             )
15             # 多选的select框
16             hobby1 = forms.MultipleChoiceField(
17                 choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
18                 label="爱好",
19                 initial=[1, 3],
20                 widget=forms.widgets.SelectMultiple()
21             )
22             # 单选的checkbox
23             keep = forms.ChoiceField(
24                 label="是否记住密码",
25                 initial="checked",
26                 widget=forms.widgets.CheckboxInput()
27             )
28             # 多选的checkbox
29             hobby2 = forms.MultipleChoiceField(
30                 choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
31                 label="爱好",
32                 initial=[1, 3],
33                 widget=forms.widgets.CheckboxSelectMultiple()
34             )

View Code

5.cookie和session

简介:

cookie与session由于http协议是无状态的 无法记录用户状态 cookie就是保存在客户端浏览器上的键值对工作原理:当你登陆成功之后 浏览器上会保存一些信息下次再访问的时候 就会带着这些信息去访问服务端  服务端通过这些信息来识别出你的身份cookie虽然是写在客户端浏览器上的  但是是服务端设置的浏览器可以选择不服从命令 禁止写cookie

session就是保存在服务器上的键值对
    session虽然是保存在服务器上的键值对
    但是它是依赖于cookie工作的

    服务端返回给浏览器一个随机的字符串
    浏览器以键值对的形式保存
    sessionid:随机字符串

    浏览器在访问服务端的时候 就会将随机字符串携带上
    后端获取随机串与后端的记录的做比对
    随机字符串1:数据1
    随机字符串2:数据2

如何操作Cookie
django返回给客户端浏览器的都必须是HttpResponse对象
return HttpResponse()
return render()
return redirect()

操作:

设置cookie利用的就是HttpResponse对象obj1.set_cookie('k1','v1')获取cookierequest.COOKIE.get()删除cookieobj1.delete_cookie("k1")设置超时时间max_age=None, 超时时间expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
    登陆功能

简易版本代码实现:

后端:

 1 def lg(request):
 2     if request.method == 'POST':
 3         username = request.POST.get('username')
 4         password = request.POST.get('password')
 5         # 就不从数据库调数据了,直接写死
 6         if username == 'jason' and password == '123':
 7             # 保存用户状态
 8             obj = redirect('/home/')
 9             obj.set_cookie('name', 'jason')  # 浏览器上就会保存键值对name:jason
10             return obj
11     return render(request,'lg.html')
12
13
14 def home(request):
15     # 先校验客户端cookie中有没有你写入的键值对
16     if request.COOKIES.get('name'):
17         return HttpResponse('home页面 只有登录了才能看')
18     return redirect('/lg/')
19
20     # return HttpResponse('home页面只有登录了才能看')

View Code

前端:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <form action="" method="post">
 9     <p>username<input type="text" name="username"></p>
10     <p>password<input type="password" name="password"></p>
11     <input type="submit">
12 </form>
13
14 </body>
15 </html>

View Code

但是以上这个方法不好,因为如果有很多个页面都需要校验,那你需要一个个的写,可以写成一个装饰器,还有一些其他的因素

升级版:功能更加完善

后端代码:

 1 def lg(request):
 2     if request.method == 'POST':
 3         username = request.POST.get('username')
 4         password = request.POST.get('password')
 5         # 就不从数据库调数据了,直接写死
 6         if username == 'jason' and password == '123':
 7             # 先获取url中的get请求携带的参数
 8             old_url = request.GET.get('next')
 9             # 判断用户是直接访问的登录页面,还是从别的页面调转过来的
10             if old_url:
11                 obj = redirect(old_url)
12             else:
13                 # 如果用户直接访问的登录页面,那么登录完成之后 直接跳到网站的首页
14                 obj = redirect('/home/')
15             obj.set_cookie('name', 'jason')  # 浏览器上就会保存键值对name:jason
16             return obj
17     return render(request,'lg.html')
18
19
20
21 # 可以写一个校验的装饰器
22 from functools import wraps
23 def login_auth(func):
24     @wraps(func)
25     def inner(request,*args,**kwargs):
26         target_url = request.get_full_path()# 后缀和get请求的参数都可以获取到
27         if request.COOKIES.get('name'):
28             res = func(request,*args,**kwargs)
29             return res
30         else:
31             return redirect('/lg/?next=%s'%target_url)
32     return inner
33
34
35 @login_auth
36 def home(request):
37     return HttpResponse('home页面只有登录了才能看')
38
39 @login_auth
40 def index(request):
41     return HttpResponse('index页面 只有登录之后才能看')
42
43 # 删除
44 def logout(request):
45     obj = redirect('/lg/')
46     obj.delete_cookie('name')
47     return obj

View Code

session:
后端:

 1 def set_session(request):
 2     # request.session['name'] = 'jason'
 3     # request.session['name1'] = 'jason1'
 4     # request.session['name2'] = 'jason2'
 5     # request.session['name3'] = 'jason3'
 6     request.session['xxx'] = 'xxx'
 7     request.session.set_expiry(30)
 8     return HttpResponse('set_session')
 9
10
11 def get_session(request):
12     # print(request.session.get('name'))
13     # print(request.session.get('name1'))
14     # print(request.session.get('name2'))
15     # print(request.session.get('name3'))
16     print(request.session.get('xxx'))
17     return HttpResponse('set_session')
18
19
20 def delete_session(request):
21     # request.session.delete('xxx')
22     request.session.flush()
23     return HttpResponse('delete_session')

View Code

详细解释:

```
session设置sessionrequest.session['name'] = 'jason'"""上面这一句话发生了三件事1.django 内部自动生成一个随机字符串2.将随机字符串和你要保存的数据 写入django_session表中(现在内存中生成一个缓存记录 等到经过中间件的时候才会执行)3.将产生的随机字符串发送给浏览器写入cookiesessionid:随机字符串"""获取sessionrequest.session.get('name')"""上面这一句话发生了三件事1.django内部会自动从请求信息中获取到随机字符串2.拿着随机字符串去django_session表中比对3.一旦对应上了就将对应的数据解析出来放到request.session中"""django session默认的超时时间是14天
```django_session表中的一条记录针对一个浏览器
```

删除session:

    # 删除当前会话的所有Session数据request.session.delete()  # 删除的是浏览器的sessionid信息# 删除当前的会话数据并删除会话的Cookie。request.session.flush()  # 将浏览器和服务端全部删除
        这用于确保前面的会话数据不可以再次被用户的浏览器访问例如,django.contrib.auth.logout() 函数中就会调用它。# 设置会话Session和Cookie的超时时间
    request.session.set_expiry(value)* 如果value是个整数,session会在些秒数后失效。* 如果value是个datatime或timedelta,session就会在这个时间后失效。* 如果value是0,用户关闭浏览器session就会失效。* 如果value是None,session会依赖全局session失效策略。总结:你在后期可以将一些数据保存到session表中,保存的数据 可以在后端任意位置获取到

转载于:https://www.cnblogs.com/zahngyu/p/11581858.html

django框架 day08相关推荐

  1. Django框架之第二篇

    Django框架之第二篇 一.知识点回顾 1.MTV模型 model:模型,和数据库相关的 template:模板,存放html文件,模板语法(目的是将变量如何巧妙的嵌入到HTML页面中). view ...

  2. Windows上python开发--2安装django框架

    Windows上python开发--2安装django框架 分类: 服务器后台开发2014-05-17 21:22 2310人阅读 评论(2) 收藏 举报 python django 上一篇文章中讲了 ...

  3. Python技术学习之Django框架设计思想

    Python是目前比较流行的计算机编程语言,据用丰富和强大的库,被称为胶水语言,能够把用其他语言制作的各种模块很轻松地联结在一起. Python功能强大,用途广泛,可广泛应用于云计算.web开发.科学 ...

  4. django框架使用mysql报错,及两种解决方法

    1.django框架 settings.py文件中部分代码: DATABASES = {# 'default': {# 'ENGINE': 'django.db.backends.sqlite3',# ...

  5. django框架--路由系统

    目录 一.路由系统理解 二.路由系统功能划分 三.路由表创建 创建工具 二级路由 路由别名 动态路由及重定向 四.自定义错误页面 五.图示路由系统在框架中的定位 六.路由系统的进阶想法 一.路由系统理 ...

  6. Python3搭建Django框架浅析

    前言 Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django 是一个开放源代码的 Web 应用框架,由 Pyt ...

  7. Django框架学习索引

    索引目录 1.Django介绍与安装 2.Django流程及模式 3.Django基本配置 4.Django模板(Templages) 1.Django的介绍和安装 3.Django框架模式 4.数据 ...

  8. Django 框架入门篇(安装与创建项目)

    什么是Django框架? 官方定义:Django是一个高级Python Web框架,鼓励快速开发和简洁实用的设计.它由经验丰富的开发人员构建,可以解决大部分Web开发的麻烦,因此您可以专注于编写应用程 ...

  9. 第九章 Django框架——csrf请求伪造和csrf_token使用

    第九章 Django框架--csrf请求伪造和csrf_token使用 一.csrf请求伪造 二.csrf_token使用 三.简单的csrf_token应用 四.Ajax使用csrf_token 一 ...

最新文章

  1. Another MySQL daemon already running with the same unix socket的解决
  2. Apache Flink 零基础入门【转】
  3. [C++STL]常用算术生成算法
  4. 利用opencv对图像和检测框做任意角度的旋转
  5. linux cmake编译安装mysql_Linux源码安装MySQL 5.6.12 (Cmake编译)
  6. nginx下虚拟目录配置301域名重定向
  7. count函数_计数函数Count、Counta、Countblank、Countif、Countifs技巧解读
  8. idea 查看jsp是否被引用_IDEA集成Java性能分析神器JProfiler
  9. jquery可见性过滤选择器:hidden、:visible
  10. 马化腾亲身分享:腾讯兵法教你做一款高口碑的产品
  11. linux java 多线程_Java多线程:Linux多路复用,Java NIO与Netty简述
  12. Android计算器代码分析
  13. μC/OS-II兼容层——让基于μC/OS-II开发的应用层无感地迁移到RT-Thread操作系统
  14. 微信小程序如何快速累计独立访客(UV)不低于 1000
  15. 8086汇编(5、进位加法)
  16. jdbc写入数据库乱码问题
  17. canvas绘制简单五子棋棋盘
  18. 平台币继续拉升,短期仍看涨
  19. Android 4.0按键事件以及系统流程分析
  20. 无线点菜服务器,ipad电子菜谱点菜

热门文章

  1. MVC教程第五篇:MVC整合Ajax
  2. word文本转换为表格 ,如果文本是以硬回车的转换方式
  3. google的几个搜索业务
  4. 漫步最优化十五——凸函数优化
  5. 漫步数学分析十二——嵌套
  6. 【转载】javascript,声明变量和导入时,大括号的特殊用法
  7. LeetCode —— 332. 重新安排行程(Python)
  8. 西瓜书——EM算法(一)
  9. 华为root工具_华为手机EMUI9 ROOT通用操作方法
  10. CButton按钮添加图片 Bitmap Icon