Python后台开发(第三章: Django高级)

Python后台开发(第三章: Django高级)

1 Cookie

1.1 Cookie机制

在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。

而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。

Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话Cookie通过在客户端记录信息确定用户身份。

1.2 什么是Cookie

  • cookie是保存在用户浏览器端的键值对
  • Cookie是由服务器生成,存储在浏览器中的键值对数据
  • 每个域名的Cookie相互独立
  • 浏览器访问域名为A的url地址,会把A域名下的Cookie一起传递到服务器
  • Cookie可以设置过期时间,默认为None,即关闭当前浏览器,Cookie立即清除.
  • 保存站点的用户数据.

1.3 Cookie原理

在这里插入图片描述

在这里插入图片描述

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

1.4 Cookie属性

1.4.1 属性表

属性 说明
set_cookie(常用) 设置Cookie的值 max_age: 默认为None
COOKIES.get(常用) 获取Cookie的值
String name 该Cookie的名称。Cookie一旦创建,名称便不可更改
Object value 该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码
int maxAge 该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1
boolean secure 该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false
String path 该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”
String domain 可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”
String comment 该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明
int version 该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

1.4.2 代码实例

1.4.2.1 set_cookie

  1. url配置
re_path('set_cookie/(.+)/(.+)',views.set_cookie_handler,name='set_cookie') 
  1. views配置
def set_cookie_handler(request,key,value): 
    response = HttpResponse() 
    #max_age=60\*60 表示Cookie的有效时间3600秒,即1小时 
    response.set_cookie(key,value,max_age= 60 * 60) 
    return response 

1.4.2.2 COOKIES.get

  1. url配置
re_path('get_cookie/(.+)',views.get_cookie_handler,name='get_cookie')
  1. views配置
def get_cookie_handler(request,key): 
    value = request.COOKIES.get(key) 
    return HttpResponse(value)

注:在测试cookie之前,需要先对Django项目执行迁移,才可以在数据库中得到对应的操作表。

1.4.3 Cookie的删除和修改

  • Cookie并不提供修改、删除操作。如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。
  • 如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆原来的Cookie。注意是0而不是负数。负数代表其他的意义。
  • 注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。

1.4.4 Cookie的域名

  • Cookie是不可跨域名的。域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie。
  • 正常情况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数,例如:
Cookie cookie = new Cookie("time","20080808"); 
// 新建Cookie cookie.setDomain(".helloweenvsfei.com");          
// 设置域名 cookie.setPath("/");                              
// 设置路径 cookie.setMaxAge(Integer.MAX_VALUE);               
// 设置有效期 response.addCookie(cookie);                       
// 输出到客户端 
  • 可以修改本机C:\WINDOWS\system32\drivers\etc下的hosts文件来配置多个临时域名,然后使用setCookie.jsp程序来设置跨域名Cookie验证domain属性。
  • 注意:domain参数必须以点(".")开始。另外,name相同但domain不同的两个Cookie是两个不同的Cookie。如果想要两个域名完全不同的网站共有Cookie,可以生成两个Cookie,domain属性分别为两个域名,输出到客户端。

1.4.5 Cookie的安全性

  1. Cookie是存储在客户端,即浏览器的,所有具有不安全性
  2. 对于敏感的数据,应该加密,或者保存在服务端

2 Session

2.1 Session机制

除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。

2.2 什么是Session

  • session是保存在服务器端的键值对。
  • Session基于Cookie的。
  • Session把敏感的数据以加密的方式保存在服务器。
  • Session默认的过期时间是两周,如果自己设置了过期时间,这样自己设定的优先级就会高于默认的
  • Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

2.3 Session原理

在这里插入图片描述

2.4 Session常用方法

属性 说明
session[key] = value 设置Session的值 设置过期时间,默认为2周: session.set_expiry(60*60)
session.get(key) 获取Session的值,如果没有这个key,返回None
flush() 删除表数据
clear() 清空sessionId对应的数据

2.5 代码实例

2.5.1 设置

  1. url配置
re_path('set_session/(.+)/(.+)',views.set_session_handler,name='set_session'), 
  1. views配置
def set_session_handler(request,key,value):
    request.session[key] = value 
    #设置过期时间 
    request.session.set_expiry(60 * 60) 
    return HttpResponse('设置成功') 

2.5.2 获取

1.url配置

re_path('get_session/(.+)',views.get_session_handler,name='get_session'), 

2.views配置

def get_session_handler(request,key): 
    value = request.session.get(key) 
    return HttpResponse(value) 

2.5.3 删除

  1. url配置
path('flush',views.flush_session_handler,name='flush'), 

  1. views配置
def flush_session_handler(request): 
    request.session.flush()

2.5.4 clear

  1. url配置
path('clear',views.clear_session_handler,name='clear'),

  1. views配置
def clear_session_handler(request): 
    request.session.clear() 
    return HttpResponse('clear')

2.6 Session—mysql

2.6.1 数据库信息配置

项目settings文件的DATABASES中配置mysql引擎。

DATABASES = { 'default': { 'ENGINE' : 'django.db.backends.mysql', 'HOST': 'localhost',
                          #一般都是localhost 
                          'PORT': '3306',
                          #本地mysql服务运行的端口号 
                          'NAME': 'django3',
                          #本地mysql库中存在设置的库 
                          'USER': 'root',
                          #用户必须为root 
                          'PASSWORD': '12345',
                          #cmd下连接mysql数据库使用的密码 } } 

2.6.2 执行迁移,生成Session表

在终端Terminal 项目目录下执行数据表更新命令:

python manag.py makemigrations # 生成迁移文件
python manag.py migrate  # 执行迁移

刷新数据库,查看是否生成了django_session表

3 Session和Cookie的区别

  • cookie数据存放在客户的浏览器上,session数据放在服务器上。
  • cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗 考虑到安全应当使用session。
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能 考虑到减轻服务器性能方面,应当使用COOKIE。
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
  • 所以个人建议: 将登陆信息等重要信息存放为SESSION 其他信息如果需要保留,可以放在COOKIE中

4 Redis数据库

4.1 Redis概述

  • 非关系型数据库
  • 数据读写的速度快
  • 可以存储的数据量少
  • 内存数据库,支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

4.2 Redis安装

  • 下载课件,找到redis—msi的安装包,也可在QQ群中下载。
  • 点击安装包,一路next,finish完成安装。
  • cmd下 输入 redis –cli ,若出现以截图,说明没有把redis的数据库添加到环境变量中

在这里插入图片描述

  • 得到以下截图结果,说明安装成功

png)]

4.3 Redis可视化工具的使用

1.接下来我们来安装Redis可视化管理工具Redis Desktop Manager

2.安装包在课件,qq群内均可下载。

3.安装参考链接:https://jingyan.baidu.com/article/925f8cb8b92debc0dde05603.html

4.4 环境搭建(模块包的安装)

pip install redis
pip install django-redis
pip install django-redis-sessions

注:若环境中存在2个Python版本,可使用pip3 进行安装,mac用户也可使用brew安装

4.5 Session—Redis的使用

在settings中配置如下信息:

SESSION_ENGINE = 'redis_sessions.session' \# 选择Redis存储Session
SESSION_REDIS_HOST = 'localhost' \# Redis的主机地址
SESSION_REDIS_PORT = 6379 \# Redis的端口号
SESSION_REDIS_DB = 0 \# 数据库编号,0-11 SESSION_REDIS_PASSWORD = '' \#
登录Redis的密码

注:完成配置,执行迁移,项目操作的session信息会通过使用的redis-session引擎将信息写入到Redis数据库中。

5 表单接收与提交

5.1 表单格式

5.1.1 基础格式

form标签 提交地址 action 提交方法 method get post 提交文件 enctype="multipart/form-data" 
例如: 
<form action="www.edu.csdn.net" method="post" enctype="multipart/form-data > 

5.1.2 input属性

属性 说明
text 文本输入框
password 密码输入框
radio 单选框
checkbox 复选框
file 文件框
button 按钮
submit 提交
reset 重置

5.1.3 下拉框

<select> 
    <option>选项1</option> 
    <option>选项2</option> 
</select>

5.1.4 大文本

<textarea cols="列数" rows="行数" > </textarea> 

5.1.5 表单代码实例

<!DOCTYPE html\> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Title</title> 
</head> 
<body> 
    <form action="{% url 'form_post' %}" > 
        username: <input type="text" name="username" ><br\> 
        hobby: <input type="checkbox" name="hobby" value="Python">Python 
        <input type="checkbox" name="hobby" value="Java">Java <br\>
        <input type="submit" value="submit"> 
    </form> 
</body> 
</html> 

5.2 请求原理

在这里插入图片描述

5.3 Get

5.3.1 提交

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Title</title> 
</head> 
<body> 
    <form action="{% url 'form_post' %}" method="get"> 
        username: <input type="text" name="username" ><br/> 
        hobby: <input type="checkbox" name="hobby" value="Python">Python 
        <input type="checkbox" name="hobby" value="Java">Java <br/> 
        <input type="submit" value="submit"> 
     </form> 
</body> 
</html>

5.3.2 接收

5.3.2.1 基础格式

value = request.GET.get([key],[默认值]) values = request.GET.getlist ([key]) 

5.3.2.2 代码实例

1.url配置

path('form_get',views.form_get_handler,name='form_get'), 

2.views配置

def form_get_handler(request): 
    username = request.GET.get('username') 
    hobbys = request.GET.getlist('hobby') 
    print('username:',username) 
    print('hobbys',hobbys) 
    return HttpResponse('')

5.4 Post

5.4.1 提交

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Title</title> 
</head> 
<body> 
    <form action="{% url 'form_post' %}" method="post"> 
        {% csrf_token %} 
        username: <input type="text" name="username" ><br/> 
        hobby: <input type="checkbox" name="hobby" value="Python">Python 
        <input type="checkbox" name="hobby" value="Java">Java <br/> 
        <input type="submit" value="submit"> 
    </form> 
</body> 
</html> 

注:Post请求,需要在表单中加入{% csrf_token %},或者取消csrf中间件

5.4.2 接收

5.4.2.1 基础格式

value = request.POST.get([key],[默认值]) values = request.POST.getlist ([key]) 

5.4.2.2 代码实例

1.url配置

path('form_post',views.form_post_handler,name='form_post'),

2.views配置

def form_post_handler(request): 
    username = request.POST.get('username') 
    hobbys = request.POST.getlist('hobby') 
    print('username:',username) 
    print('hobbys',hobbys) 
    return HttpResponse('') 

6 csrf跨域攻击

6.1 原理

在这里插入图片描述

1.在django的任何post请求,都会在请求之初,给用户下发一下串用来校验身份的编码,并且每次请求不一样。

2.如果不加csrf_token校验,会发生csrf错误

在这里插入图片描述

3.使用django的csrf校验,{% csrf_token
%}标签实际上就是在前端的form表单当中生成了一个hidden隐藏域,name为csrfmiddlewaretoken,value是csrf校验的值

在这里插入图片描述

6.2 解决跨域攻击

  1. 关闭中间件

在这里插入图片描述

  1. 表单加入{% csrf_token %}

在这里插入图片描述

6.3 代码实例

1.定义表单

在这里插入图片描述
2.url

在这里插入图片描述
3.视图文件, 完成注册

在这里插入图片描述

7 模型类多表操作

7.1 基本原则

  • 一对一的表,两表的属性实际上完全可以合并成一个表,共用一个主键即可;
  • 一对多的表,可以设中间关联表,也可以将关联表并入“多”这头;若设独立关联表,则可引入“多”这头的主键作为其主键,也可另立主键并将“一”和“多”两表的主键作为关联表的外键;
  • 多对多的表,则必须通过Django创建管理中间关联表,关联表设独立主键,并引入两个“多”头的表的主键作为关联表的外键。
  • 能用1对1的,就不用1对多;能用1对多的,就不用多对多,往简单化方向靠;
  • 能当属性处理的,尽量当属性,而不是当实体处理去另立新表,这样可使问题简化。
  • 把意义相近联系紧密的属性放在一张表内,而不是拆在多张表中。

7.2 外键种类

关键字 说明
ForeignKey 一对多 定义在多的一端中
ManyToManyField 多对多 定义在任意一方
OneToOneField 一对一 定义在任意一方

7.3 外键常用参数

关键字 说明
to 引用的模型类
on_delete 外键约束 on_delete=models.CASCADE 级联操作(多对一,一的一方删除,多的一方也删除) on_delete=models.PROTECT 报异常(被引用的一方不能删除) on_delete=models.SET_NULL 设置为null(多对一,一的一方删除,多的一方外键为null) on_delete=models.DO_NOTHING 什么也不做
related_name 反向引用,如果两个表间有多种外键关系,需要指明related_name

7.4 一对一

7.4.1 概念

  • 子表从母表中选出一条数据一一对应,母表中选出来一条就少一条,子表不可以再选择母表中已被选择的那条数据
  • 一般用于某张表的补充,比如用户基本信息是一张表,但并非每一个用户都需要有登录的权限,不需要记录用户名和密码,此时,合理的做法就是新建一张记录登录信息的表,与用户信息进行一对一的关联,可以方便的从子表查询母表信息或反向查询
  • 当某个对象想扩展自另一个对象,那可以再这个对象的主键上添加一对一的关系
  • 当某个对象想扩展自另一个对象,那可以再这个对象的主键上添加一对一的关系

7.4.2 代码实例

7.4.2.1 模型层的建立

# 通过 OneToOneField 创建一对一的关系 
from django.db import models 
class StaffInfo(models.Model):
    name = models.CharField(max_length=32, null=True) 
    age = models.CharField(max_length=32, null=True) 
class Salary(models.Model): 
    money = models.CharField(max_length=32, null=True) 
    staff = models.OneToOneField("StaffInfo")

7.4.2.2 增删改查

# 增 和普通一样

models.StaffInfo.objects.create(name="xxx",age=12)models.Salary.objects.create(money=3000, staff_id=2)

#一对一关联的外键如果添加重复会报错,也就是说django已经帮我们做好了唯一索引
# 删 和普通的也是一样的

models.Salary.objects.filter(staff_id=2).delete()
#也有级联删除的问题, 可以通过on_delete 修改值取消级联删除改 和普通也一样
models.Salary.objects.filter(staff_id=2).update(money=2000)

# 查分为正查和反差两种
# 正查 通过点表中外键名跨表查询 row.staff.nameres = models.Salary.objects.all()
for row in res:
	print(row.money, row.staff.name)
# 反差点关联表的表明小写进行跨表查询 row.salary.money
res = models.StaffInfo.objects.all()
for row in res:
	print(row.name, row.salary.money)

7.5 一对多

7.5.1 概念

  • 通过外键来进行2张表的关联操作
  • 子表从母表中选出一条数据一一对应,但母表的这条数据还可以被其他子表数据选择

7.5.2 代码实例

7.5.2.1 模型层的建立

from django.db import models 
class User1(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
	# 用户名 
class Forum1(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 帖子主题 
    # 发帖的用户 
    userObject = models.ForeignKey( to=User1, on_delete=models.CASCADE) 
    # ‘一’的一方的类 
    # 级联操作 

7.5.2.2 添加与查询

# 添加用户 
user = User1.objects.create(name='name1') 
# 添加帖子,引用上面创建的用户 
Forum1.objects.create(name='topic1',userObject=user) 
# 得到用户发的所有帖子 \# 一对多,【多的一方的class名小写_set】 
forum_s = User1.objects.get(id=1).forum1_set.all() print(forum_s)
# 得到帖子发送者对象 
# 多对一,【通过定义的外键字段引用】 
user = Forum1.objects.get(name='topic1').userObject print(user) 
'''【结果】 
<QuerySet [<Forum1: Forum1 object>]> > User1 object 
''' 

7.5.2.3 引用关系

在这里插入图片描述

注:

M —>表示1对多

M得到引用的:通过M中定义的外键字段得到
得到被应用的所有M:通过M方的类名_set,返回时QuerySet对象,例如user1.forum1_set.all()

7.5.2.4 多对一的自关联

使用to = ‘self’ 实现自关联,推荐使用django来维护一对多的自关联模型

  1. model.py
class Area(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 地区名字 
    pArea = models.ForeignKey(to='self',null=True) 
    # 上一级地区的引用 
    def __str__(self): 
        return str(self.name) 

  1. 测试
# area1:北京 
area1 = Area.objects.create(name='北京') 
# area2:朝阳 
area2 = Area(name='朝阳') 
# 设置area2的父地区是area1北京 
area2.pArea = area1 area2.save() 
# area3:丰台 
area3 = Area.objects.create(name='丰台') 
# area1北京的子地区,添加area3丰台 
area1.area_set.add(area3) 
area_beijing = Area.objects.get(name='北京') 
area_chaoyang = Area.objects.get(name='朝阳') 
area_fengtai = Area.objects.get(name='丰台') 
# 打印北京的所有子区域 
print(area_beijing.area_set.all()) 
# 打印朝阳的父区域 
print(area_chaoyang.pArea) 
'''
【结果】
<QuerySet [<Area: 朝阳>, <Area: 丰台>]>  北京
'''

7.6 多对多

7.6.1 概念

  • 建立.多对多模型关系,Django会自己建立,维护一个中间表。
  • django会自动创建一个中间表:名称:【app名】【类名小写】【类名小写】
  • 添加引用关系方法:add()
  • 删除引用关系方法:remove()

7.6.2 测试

7.6.2.1 模型层的建立

class User2(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 用户名 
    def __str__(self): 
        return str(self.name) 
class Hobby2(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 爱好名称 
    userobjects = models.ManyToManyField(to=User2) 
    # 多对多 
    def __str__(self): 
        return str(self.name) 

7.6.2.2 增删改查

user1 = User2.objects.create(name='name1') 
user2 = User2.objects.create(name='name2') 
# 创建3个爱好对象 
hobby1 = Hobby2.objects.create(name='早上写代码') 
hobby2 = Hobby2.objects.create(name='中午写代码') 
hobby3 = Hobby2.objects.create(name='晚上写代码') 
# 通过用户,添加引用 
user1.hobby2_set.add(hobby1) 
user1.hobby2_set.add(hobby2) 
# 通过爱好,添加引用 
hobby3.userobjects.add(user1) 
hobby3.userobjects.add(user2) 
print(user1.hobby2_set.all()) 
print(hobby3.userobjects.all()) 
# hobby3删除引用的user1 
hobby3.userobjects.remove(user1) 
print(hobby3.userobjects.all()) 
'''【结果】 [<Hobby2: 中午写代码>, <Hobby2: 早上写代码>, <Hobby2: 晚上写代码>] <QuerySet [<User2: name1>, <User2: name2>]> <QuerySet [<User2: name2>]> 
'''

print(row.money, row.staff.name)
# 反差 点关联表的表明小写进行跨表查询 row.salary.money
res = models.StaffInfo.objects.all()
for row in res:
	print(row.name, row.salary.money)

7.6.3 through维护中间表

through指明中间表的模型类,如果自己指明了中间表,那么django就不会帮助维护了,所有的添加删除引用关系,都必须自己手动完成。

  1. model.py
class User3(models.Model): 
    name = models.CharField(max_length=16, unique=True) 
    # 用户名 
    def __str__(self): 
        return str(self.name) 
class Hobby3(models.Model): 
    name = models.CharField(max_length=16, unique=True) 
    # 爱好名称
    userobjects = models.ManyToManyField(to=User3,through='User3ToHobby3') 
    # 多对多 
    def \__str__(self): 
        return str(self.name) 
class User3ToHobby3(models.Model): 
    user = models.ForeignKey(to=User3) 
    hobby = models.ForeignKey(to=Hobby3)

  1. 测试
# 创建用户对象 
user1 = User3.objects.create(name='name1') 
user2 = User3.objects.create(name='name2') 
# 创建爱好对象 
hobby1 = Hobby3.objects.create(name='早上写代码') 
hobby2 = Hobby3.objects.create(name='中午写代码') 
hobby3 = Hobby3.objects.create(name='晚上写代码') 
# 自己手动维护中间表 
User3ToHobby3.objects.create(user=user1,hobby=hobby1) User3ToHobby3.objects.create(user=user1,hobby=hobby2) User3ToHobby3.objects.create(user=user2,hobby=hobby2) User3ToHobby3.objects.create(user=user2,hobby=hobby3) 
print(user1.hobby3_set.all()) 
print(hobby3.userobjects.all()) 
'''【结果】 >> <QuerySet [<Hobby3: 早上写代码>, <Hobby3: 中午写代码>]
		  >> <QuerySet [\<User3: name2\>]\> 
'''

7.7 一对多 多对多 一对一的详细实例

参考以下链接: https://blog.csdn.net/jiangbo721/article/details/89918381

8 中间件Middleware应用

8.1 概念

中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出

8.2 原理

在http请求 到达视图函数之前 和视图函数return之后,django会根据自己的规则在合适的时机执行中间件中相应的方法。Django1.9版本以后中间件的执行流程

  • 执行完所有的request方法 到达视图函数。
  • 执行中间件的其他方法
  • 经过所有response方法 返回客户端。

注意:如果在其中1个中间件里 request方法里return了值,就会执行当前中间件的response方法,返回给用户 然后报错。。不会再执行下一个中间件。

在这里插入图片描述

在这里插入图片描述

8.3 中间件的注册

settings.py文件内设置MIDDLEWARE的值。

在这里插入图片描述

8.4 方法详解

8.4.1 init

没有参数,服务器响应第一个请求的时候自动调用,用户确定是否启用该中间件

8.4.2 process_request(self,request) 常用

  • 在执行视图前被调用,每个请求上都会调用
  • 不返回或返回HttpResponse对象
  • 没有return或者return None 继续调用其他视图
  • return response 则不会调用其他视图

8.4.3 process_view(self,request,view_func,view_args,view_kwargs)

调用视图之前执行,每个请求都会调用2.不返回或返回HttpResponse对象

8.4.4 process_template_response(self,request,response)

在视图刚好执行完后进行调用,每个请求都会调用2.不返回或返回HttpResponse对象

8.4.5 process_response(self,request,response)

所有响应返回浏览器之前调用,每个请求都会调用2.不返回或返回HttpResponse对象3.必须return response

8.4.6 process_exception(self,request,exception)

  • 当视图抛出异常时调用
  • 不返回或返回HttpResponse对象

8.5 使用场景

由于中间件工作在
视图函数执行前、执行后(像不像所有视图函数的装饰器!)适合所有的请求/一部分请求做批量处理

  • 做IP限制
    • 放在 中间件类的列表中,阻止某些IP访问了;
  • URL访问过滤
    • 如果用户访问的是login视图(放过)如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在多个视图函数上写装饰器了!
    • 缓存(还记得CDN吗?)
  • 客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层
    执行视图函

9 admin后台管理

9.1 概念

  • django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查
  • 管理界面不是让访问网站的人使用的,它服务于网站管理者。 它用于网站的管理员。

9.2 创建管理员用户

  • 打开treminal 输入 python manage.py createsuperuser 然后回车
  • 自定义用户名,密码,邮箱号

在这里插入图片描述

注: 输入密码是 密码是不可见的,输入时需要注意,.

9.3 admin登录

  • 打开主路由自带的admin路由

在这里插入图片描述

  • 启动服务,在前台输入url127.0.0.1/端口号/admin
  • 输入刚才自定义的账号密码进行登录

9.4 admin管理后台

9.4.1 admin.py

9.4.1.1 参数详解

参数 说明
@admin.register(模型类) 在后台注册导入的模型类
list_display 定义展示的字段
search_fields 定义支持模糊查询的字段
filter_horizontal 定义多表显示
list_filter 定义右侧的过滤器
admin.site.site_header 设置网站页头
admin.site.site_title 设置页面标题
admin.site.index_title 设置首页标语

9.4.1.2 代码实例

在这里插入图片描述

在这里插入图片描述

9.4.2 app.py

9.4.2.1 参数详解

参数 说明
verbose_name 定义app显示的名字

9.4.2.2 代码实例

在这里插入图片描述

9.4.3 model.py

9.4.3.1 参数详解

参数 说明
Blank 默认为Fasle 添加字段时不允许为空
Choices 下拉选框和模型类字段的绑定, Django中推荐CHOICES大写
related_name 自定义表的外键,用于模型类的反向查找
upload_to 定义上传文件的保存方法

9.4.3.2 代码实例

在这里插入图片描述

在这里插入图片描述

10 项目浅析

10.1 项目结构

10.1.1 static

存放项目中使用的 css,js,img,video文件

10.1.2 templete

存放项目中使用的前端html文件。

10.1.3 user

1.定义用户的模型类。

2.指定后台管理显示的内容。

3.用户的注册,登录,退出 。

4.购物车的 显示,增加,购买。

10.1.4 course

1.定义课程的模型类,图片和视频的保存方式。

2.指定后台管理显示的内容。

3.前台主页课程的显示。

4.课程详情页的加载。

5.视频的播放

10.1.5 middleware

1.全局context的定义

2.前台登录后用户的显示。

3.用户的登陆判断,若没登录则跳转登录页面

10.1.6 settings

10.1.6.1 INSTALLED_APPS

应用的加载

在这里插入图片描述

10.1.6.2 MIDDLEWAER

添加自定义的中间件文件

在这里插入图片描述

10.1.6.3 TEMPLATES

在这里插入图片描述

10.1.6.4 DATABASES

在这里插入图片描述

注:数据库和密码换成自己本地使用的数据库和密码

10.1.6.5 语言和时区

在这里插入图片描述

10.1.6.6 static静态文件

在这里插入图片描述

10.2 项目运行

10.2.1 数据库迁移

在这里插入图片描述

在这里插入图片描述

10.2.2 后台管理员的创建

在这里插入图片描述

10.2.3 后台数据的添加

1.启动服务

在这里插入图片描述

2.访问项目

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注:访问http://127.0.0.1:8000/admin 路由进行后台用户的登录.

在这里插入图片描述

4a83c85fd0961f7fbe63b83dca095944.png

注:添加用户,课程种类,课程表.

在这里插入图片描述

10.3 功能解析

10.3.1主页课程的展示

在这里插入图片描述

10.3.2 主页登录,注销和用户信息显示

在这里插入图片描述

在这里插入图片描述

10.3.3 课程详情页的展示.

在这里插入图片描述

在这里插入图片描述

10.3.4 购物车操作:加入,购买

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
注:user_shoppingcart.html中url快捷调用user_purcharse,携带课程id,完成购买。

10.3.4 课程观看

在这里插入图片描述

发布了374 篇原创文章 · 获赞 1811 · 访问量 210万+

猜你喜欢

转载自blog.csdn.net/CSDNedu/article/details/103353621