Django之中间件&信号&缓存&form上传
中间件
1、中间件是什么?
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。 就是存在socket和视图函数中间的一种相当于过滤的机构。
中间件共分为:
(1)process_request(self,request) 接受request之后确定所执行的view之前
(2)process_view(self, request, callback, callback_args, callback_kwargs) 确定了所要执行的view之后 view真正执行之前
(3)process_template_response(self,request,response) view 执行之后,只有在视图函数的返回对象中有render方法才会执行!
(4)process_exception(self, request, exception) view抛出异常
(5)process_response(self, request, response)
2.能做过什么?
1、做IP限制
放在 中间件类的列表中,阻止某些IP访问了;
2、URL访问过滤
如果用户访问的是login视图(放过)
如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了!
3、缓存(还记得CDN吗?)
客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数
3、
注意:
对于所有请求的批量做处理的时候用中间件
单独对某几个函数做处理的时候用装饰器
步骤:
1、、先建一个文件夹,里面写一个py文件
2、、然后开始写类
1.中间件就是一个类,类里面写几个方法
class M1(MiddlewareMixin): 必须继承
def process_request(self,request): request:请求里面的所有的东西
print("m1.request_request")
这个方法里面别轻易返回值,要是有返回值就不再继续执行后面的了,执行自己的process_response和上边的response
一般是无返回值的:继续执行后续的中间件和视图函数
def process_response(self,request,response):
return response 2.在settings中的MIDDLEWARE加上路径
文件夹名称.py文件名称.类名
3.找到继承的那个类,吧那个类拿过来
一般不要用导入的方法,不然有时候更新了就没有这个类了,你就把它继承的那个类拿过来,
中间件执行流程:
用户有访问请求,会从中间件最上方的request(接收)一直往下执行,最后到视图函数然后再由中间件从下往上的response(返回)给用户

中间件执行过程中有return值流程:用户有访问请求,会从中间件最上方的request(接收)一直往下执行,直到那个中间件有return值后在当前的中间值返回给用户,(在1.7左右版本)会直接跳到最后的中间件,然后返回给用户。


中间件代码:


Django中的信号及其用法
Django中提供了"信号调度",用于在框架执行操作时解耦.
一些动作发生的时候,系统会根据信号定义的函数执行相应的操作
Django中内置的signal
Model_signals
pre_init # Django中的model对象执行其构造方法前,自动触发
post_init # Django中的model对象执行其构造方法后,自动触发
pre_save # Django中的model对象保存前,自动触发
post_save # Django中的model对象保存后,自动触发
pre_delete # Django中的model对象删除前,自动触发
post_delete # Django中的model对象删除后,自动触发
m2m_changed # Django中的model对象使用m2m字段操作数据库的第三张表(add,remove,clear,update),自动触发
class_prepared # 程序启动时,检测到已注册的model类,对于每一个类,自动触发
Managemeng_signals
pre_migrate # 执行migrate命令前,自动触发
post_migrate # 执行migrate命令后,自动触发
Request/response_signals
request_started # 请求到来前,自动触发
request_finished # 请求结束后,自动触发
got_request_exception # 请求异常时,自动触发
Test_signals
setting_changed # 配置文件改变时,自动触发
template_rendered # 模板执行渲染操作时,自动触发
Datebase_Wrapperd
connection_created # 创建数据库连接时,自动触发
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,系统会自动触发注册函数
例子,创建数据库记录,触发pre_save和post_save信号
创建一个Django项目,配置好路由映射
models.py中的代码:
from django.db import models class UserInfo(models.Model):
name=models.CharField(max_length=32)
pwd=models.CharField(max_length=64)
views.py中的代码:
from django.shortcuts import render,HttpResponse
from app01 import models def index(request):
models.UserInfo.objects.create(name="mysql",pwd="mysql123")
return HttpResponse("ok")
项目的__init__.py文件中代码:
from django.db.models.signals import pre_save,post_save
def pre_save_func(sender,**kwargs):
print("pre_save_func")
print("pre_save_msg:",sender,kwargs)
def post_save_func(sender,**kwargs):
print("post_save_func")
print("post_save_msg:",sender,kwargs)
pre_save.connect(pre_save_func) # models对象保存前触发callback函数
post_save.connect(post_save_func) # models对象保存后触发函数
创建一个index.html网页,用浏览器打开这个项目,在服务端后台打印信息如下:
pre_save_func
pre_save_msg: <class 'app01.models.UserInfo'> {'signal': <django.db.models.signals.ModelSignal object at 0x0000000002E62588>,
'instance': <UserInfo: UserInfo object>, 'raw': False, 'using': 'default', 'update_fields': None} post_save_func
post_save_msg: <class 'app01.models.UserInfo'> {'signal': <django.db.models.signals.ModelSignal object at 0x0000000002E62630>,
'instance': <UserInfo: UserInfo object>, 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'}
比较打印的结果,可以看到models对象保存后,在打印信息里包含一个"create=True"的键值对.


也可以使用装饰器来触发信号,把上面__init__.py中的代码修改:
from django.core.signals import request_finished
from django.dispatch import receiver @receiver(request_finished)
def callback(sender, **kwargs):
print("Request finished!")
则在本次请求结束后自动触发callback函数,在后台"request finished"这句话.
自定义信号
1.定义信号
新建一个项目,配置好路由,在项目根目录下创建一个singal_test.py的文件,内容为
import django.dispatch action=django.dispatch.Signal(providing_args=["aaaa","bbbb"])
2.注册信号
项目应用下面的__init__.py文件内容:
from singal_test import action
def pre_save_func(sender,**kwargs):
print("pre_save_func")
print("pre_save_msg:",sender,kwargs)
action.connect(pre_save_func)
3.触发信号
views视图函数内容:
from singal_test import action action.send(sender="python",aaa="",bbb="")
用浏览器打开index.html网页,后台打印信息如下:
pre_save_func
pre_save_msg: python {'signal': <django.dispatch.dispatcher.Signal object at 0x000000000391D710>, 'aaa': '', 'bbb': ''}
由于内置信号的触发者已经集成到Django中,所以会自动调用,而对于自定义信号需要在任意位置触发
Django 之缓存
一、缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1、配置
a、开发调试
# 此为开始调试用,实际内部不做任何操作
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
'TIMEOUT': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
'KEY_PREFIX': '', # 缓存key的前缀(默认空)
'VERSION': 1, # 缓存key的版本(默认1)
'KEY_FUNCTION' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
}
} # 自定义key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys. Constructs the key used by all other methods. By default it prepends
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
return '%s:%s:%s' % (key_prefix, version, key) def get_key_func(key_func):
"""
Function to decide which key function to use. Defaults to ``default_key_func``.
"""
if key_func is not None:
if callable(key_func):
return key_func
else:
return import_string(key_func)
return default_key_func
b、内存
# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
} # 注:其他配置同开发调试版本
c、文件
# 此缓存将内容保存至文件
# 配置: CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
# 注:其他配置同开发调试版本
d、数据库
# 此缓存将内容保存至数据库
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表
}
}
# 注:执行创建表命令 python manage.py createcachetable
e、Memcache缓存(python-memcached模块)
# 此缓存使用python-memcached模块连接memcache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
f、Memcache缓存(pylibmc模块)
# 此缓存使用pylibmc模块连接memcache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
2、应用
@cache_page(15) #超时时间为15秒,这15秒是暂存的状态,当过了15秒又是新状态了
a. 全站使用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
# 其他中间件...
'django.middleware.cache.FetchFromCacheMiddleware',
]
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 单独视图缓存
方式一:
from django.views.decorators.cache import cache_page @cache_page(60 * 15)
def my_view(request):
... 方式二:
from django.views.decorators.cache import cache_page urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]
c、局部视图使用
a. 引入TemplateTag
{% load cache %}
b. 使用缓存
{% cache 5000 缓存key %}
缓存内容
{% endcache %}
Django之文件上传
使用Django框架进行文件上传共分为俩种方式
|
1
2
3
|
一、方式一通过form表单进行文件上传 |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#=========================================FORM表单上传文件========================================def f1(request):#定义f1上传函数 if request.method=='GET':#如果是以GET请求 return render(request,'f1.html')#返回html模板 else:#否则 import os#导入模块 file_obj=request.FILES.get('fafafa')#通过文件的方式获取文件 f=open(os.path.join('static',file_obj.name),'wb')#打开一个文件创建一个文件句柄,写的模式打开 for chunk in file_obj.chunks():#循环对象(chunks是块 代表大小的意思) f.write(chunk)#循环获得对象并写到文件中 f.close()#通过文件句柄,关闭文件 return render(request,'f1.html')#返回到html模板 |
form表单上传文件
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
========================form表单html============================<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><form action="/f1/" method="POST" enctype="multipart/form-data"> {% csrf_token %} <p><input type="text" name="user"></p> <p><input type="file" name="fafafa"></p> <p><input type="submit" value="提交"></p></form></body></html> |
|
1
2
3
|
一、方式二通过form组件进行文件上传 |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#======================================Form组件上传文件========================================class F2Form(Form):#定义一个上传类 user=fields.CharField()#字段是字符串类型 fafafa=fields.FileField()#字段是文件类型def f2(request):#定义一个f2上传文件的函数 import os#导入模块 if request.method=='GET':#如果请求方式GET obj=F2Form()#实例化一个对象 return render(request,'f2.html',{'obj':obj})#携带obj对象返回html else:#否则 obj=F2Form(data=request.POST,files=request.FILES)#实例化对象obj前端标签input获取的数据以request.POST接收,文件信息以request.FILES接收 if obj.is_valid():#通过form组件进行校验如果校验成功就执行下边代码 print(obj.cleaned_data.get('fafafa').name)#打印文件名称 print(obj.cleaned_data.get('fafafa').size)#打印文件大小 f=open(os.path.join('static',obj.cleaned_data.get('fafafa').name),'wb')#打开文件并创建文件句柄,以写的模式打开 for chunk in request.FILES.get('fafafa').chunks():#循环读取文件对象的内容 f.write(chunk)#循环写入到文件中 f.close()#通过文件句柄将文件关闭 return render(request,'f2.html',{'obj':obj})#携带obj对象返回html模板 |
form组件上传文件
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><form method="POST" action="/f2/" enctype="multipart/form-data"> {% csrf_token %} <p>{{ obj.user }}</p> <p>{{ obj.fafafa }}</p> <input type="submit" value="提交" /> </form></body></html> |
Django之中间件&信号&缓存&form上传的更多相关文章
- .net core 3.0web_razor page项目_使用中间件接受大文件上传报错_httpRequest.Form threw an exception of type Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException_Request body too large
前言:在web项目的.net framework时文件上传时,自己常用一般处理程序接受上传文件,上传文件的大小限制是可以项目的webconfig里配置. 到core项目使用一般处理程序变成了中间件 ...
- django 12天(跨域,文件上传,下载,cookie,session)
django 12天(跨域,文件上传,下载) 跨域 什么是跨域 1.协议不同 2.端口不同 3.主机不同 如何解决跨域 1.安装django-cors-headers模块 2.在settings.py ...
- Django项目实战之用户头像上传与访问
1 将文件保存到服务器本地 upload.html <!DOCTYPE html> <html lang="en"> <head> < ...
- Django实现注册页面_头像上传
Django实现注册页面_头像上传 Django实现注册页面_头像上传 1.urls.py 配置路由 from django.conf.urls import url from django.cont ...
- Django:学习笔记(8)——文件上传
Django:学习笔记(8)——文件上传 文件上传前端处理 本模块使用到的前端Ajax库为Axio,其地址为GitHub官网. 关于文件上传 上传文件就是把客户端的文件发送给服务器端. 在常见情况(不 ...
- c# 模拟表单提交,post form 上传文件、大数据内容
表单提交协议规定:要先将 HTTP 要求的 Content-Type 设为 multipart/form-data,而且要设定一个 boundary 参数,这个参数是由应用程序自行产生,它会用来识别每 ...
- c# 模拟表单提交,post form 上传文件、数据内容
转自:https://www.cnblogs.com/DoNetCShap/p/10696277.html 表单提交协议规定:要先将 HTTP 要求的 Content-Type 设为 multipar ...
- django 常用方法总结 < 手写分页-上传头像-redis缓存,排行 ...>
1.不使用自带模块<Paginator>的手写分页功能views.pydef post_list(request): page = request.GET.get('page', 1) # ...
- django之中间件、缓存、信号、admin内置后台
目录: 中间件 缓存 信号 admin后台 一.中间件 1.什么是中间件? 中间件是一个.一个的管道,如果相对任何所有的通过Django的请求进行管理都需要自定义中间件 中间件可以对进来的请求和出去的 ...
随机推荐
- golang编译库文件方式
// as c-shared library $ go build -buildmode=c-shared -o nautilus.a nautilus.go // as c-archive $ go ...
- SQL DML 数据操纵语句
前言 DML(Data Manipulation Language)语句:数据操纵语句,用于添加.删除.更新和查询数据库记录,并检查数据完整性.常用的语句关键字主要包括 insert.delete.u ...
- Effective Java 第三版——72. 赞成使用标准异常
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- python3 + flask + sqlalchemy +orm(2):数据库中添加表
往数据库中添加一张保存文章的表,表明为article,字段有id,title,content 同样一个配置文件:config.py DEBUG = True #dialect+driver://roo ...
- 谈谈tmpdir与innodb_tmpdir的区别和用处
[背景] innodb_tmpdir是在innodb online ddl中提到的一个参数:大致的意思是innodb在做online-ddl的时候会向临时目录写入“临时排序文件” 而这些文件的大小基本 ...
- Atitit s2018 s3 doc list alldvc.docx .docx s2018 s3f doc compc s2018 s3f doc homepc sum doc dvcCompc dtS312 s2018 s3f doc compc\Atitit PathUtil 工具新特性新版本 v8 s312.docx s2018 s3f doc compc\Atitit 操作日
Atitit s2018 s3 doc list alldvc.docx .docx s2018 s3f doc compc s2018 s3f doc homepc sum doc dvcCompc ...
- 大话Json对象和Json字符串
一.Json对象和Json字符串的区别 (1)Json对象:可以通过javascript存取属性. 先介绍一下json对象,首先说到对象的概念,对象的属性是可以用:对象.属性进行调用的.例如: var ...
- Oracle分析函数-keep(dense_rank first/last)
select * from criss_sales where dept_id = 'D02' order by sale_date ; 此时有个新需求,希望查看部门 D02 内,销售记录时间最早,销 ...
- Spark基础
1 读取本地文件 ./spark-shell scala> val textFile=sc.textFile("file:///home/hadoop/wordfile1.txt&qu ...
- java jdk 打开出错 Failed to load the JNI shared library
``` Failed to load the JNI shared library 解决方法 换了JDK 32位x86的 打开32位 eclipse 2017 oxygen 出现这个问题,修改 配置文 ...