Python学习----第七模块笔记(Web开发进阶之Django基础)
1、Django简介
1.1、Web框架
Web框架(web framework)或者叫做Web应用框架(web application framework),是用于进行web开发的一套软件结构。大多数的web框架提供了一套开发和部署网站的方式,为web行为提供了一套支持方法。使用web框架,很多业务逻辑外的功能不需要自己再去完善,而是使用框架已有的功能就可以了。
Web框架可分为MVC(Model模型、Views视图、Controller控制器)和MTV(Model模型、Templates模板、Views视图)。
1.2、Django简介
Django是一个流行的开源的基于Python的重量级Web框架,集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。Django使用了MTV模式。
Django的设计十分优美:
- 对象关系映射(ORM),以Python类形式定义你的数据模型,ORM将模型与关系数据库连接起来,你将得到一个非常容易使用的数据库API,同时你也可以在Django中使用原始的SQL语句。
- URL分派,使用正则表达式匹配URL,你可以设计任意的URL,没有框架的特定限定。像你喜欢的一样灵活。
- 模板系统,使用Django强大而可扩展的模板语言,可以分隔设计、内容和Python代码。并且具有可继承性。
- 表单处理,你可以方便的生成各种表单模型,实现表单的有效性检验。可以方便的从你定义的模型实例生成相应的表单。
- 缓存系统,可以挂在内存缓冲或其它的框架实现超级缓冲 -- 实现你所需要的粒度。
- 会话(Session),用户登录与权限检查,快速开发用户会话功能。
- 自动化的管理界面,不需要你花大量的工作来创建人员管理和更新内容。Django自带一个ADMIN site,类似于内容管理系统。
2、Django安装及配置
2.1、Django的安装
Django官网https://www.djangoproject.com/。
使用pip install django即可安装Django。当前使用pip安装的Django版本为2.0.3。
2.2、Django工程创建及目录详解
安装Django后,即可使用以下命令创建Django工程:
django-admin startproject 工程名称
Django工程创建完成后,在指定目录将出现以下结构的目录:
工程名称/ | | -- 工程名称/ | | -- init.py | | -- settings.py # Django的配置文件 | | -- urls.py # Django路由系统 | | -- wsgi.py # Django遵循WSGI规范 | | -- manage.py # Django的管理功能 | | -- templates/ # 使用IDE创建工程时会自动创建,用于存放模板文件(即HTML)
启动该Django工程:
# 在工程目录下运行 python manage.py runserver host:port
2.3、Django创建APP及APP目录详解
创建APP的目的在于将业务逻辑分开,每个具体的APP实现一个具体的业务。
使用以下命令创建APP:
python manage.py startapp app名称
创建完APP后,将出现以下结构的目录:
# 从APP目录开始 APP名称/ | | -- migrations/ # 创建或修改数据库表结构时会在该文件夹下创建记录 | | -- admin.py # Django提供的后台管理功能 | | -- apps.py # 用于配置当前的APP | | -- models.py # Django提供的ORM,通过类即可创建数据库结构 | | -- tests.py # 单元测试 | | -- views.py # 视图文件,编写业务代码
2.4、Django配置模板路径及静态文件路径
配置模板路径:
# 在settings.py中的TEMPLATES = 下修改 'DIRS': [os.path.join(BASE_DIR, "templates")],
配置静态文件路径:
# 静态文件目录可命名为static # 在settings.py文件中的STATIC_URL = '/static/'下添加 STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), )
3、使用Django
3.1、Django请求的生命周期
连接Django请求的整个生命周期,我们就可以根据该周期来使用Django。
当用户的请求到来时,首先到达的是Django的路由系统,Django根据路由系统里面的配置把请求转给相应的视图函数,视图函数根据请求的具体内容从模板或数据库中提取数据之后经过渲染后返回给用户。整个生命周期如下:
用户请求 ---> 中间件 ---> 路由系统 ---> 视图函数 ---> 模板渲染 ---> 展示给用户最终结果
3.2、中间件
在Django中,中间件其实就是一个类,在请求到来和结束之后,Django会根据自己的规则在合适的时机执行中间件中相应的方法。
中间件在settings.py中的MIDDLEWARE = []中配置,里面的每一个项即为一个中间件。
自定义中间件:
# 在xx目录下创建xxx.py文件 from django.utils.deprecation import MiddlewareMixin class F1(MiddlewareMixin): # 中间件中可以定义以下五种方法 def process_request(self, request): # 请求来时首先通过该方法 pass # 不能return,否则无法到达Views函数 def process_view(self, request, callback, callback_args, callback_kwargs): # 所有中间件的request方法执行完成,URL匹配成功并获取Views函数的名称和参数后执行该方法(Views函数不执行) pass def process_template_response(self, request, response): # 只有在Views函数的返回值中有render方法时执行 pass def process_exception(self, request, exception): # 只有在Views函数出错时执行 pass def process_response(self, response): # 中间件其他方法或Views函数执行完成后执行 pass return response # 必须return response,否则前一个中间件无法获取到返回值 # 以上方法的返回值可以是None和HttpResponse对象。如果是None,则继续按照Django定义的规则向下执行,如果是HttpResponse对象,则直接将该对象返回给用户 # 在settings.py中注册中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'xx.xxx' # 根据中间件需要在合适执行决定放置位置 ]
中间件的整个执行过程:
3.3、路由系统
Django的路由系统就是URL与视图函数的对应关系,在urls.py文件中配置。Django支持一个URL对应一个视图函数、一组URL(使用正则表达式)对应一个视图函数。
一个URL对应一个视图函数:
# 在urls.py文件中添加 urlpatterns = [ path('admin/', admin.site.urls), # Django自带的后台管理 path('URL', 视图函数), ]
一组URL对应一个视图函数:
# 在urls.py文件中添加 urlpatterns = [ re_path('URL带正则表达式', 视图函数), ] e.g: urlpatterns = [ re_path('home-(\d+)', 视图函数), ] # 使用多少个正则表达式,就会向视图函数传递相应数量的参数,视图函数必须接收这些参数,可以设置*args和**kwargs # 推荐使用正则表达式分组 e.g: urlpatterns = [ re_path('home-(?<Pnid>\d+)', 视图函数), ]
添加默认值:
# 在URL中添加默认值 urlpatterns = [ path('URL', 视图函数, {"xx": "xxx"}), ] # 在视图函数中必须接收该默认值 def func(request, xx): print(xx)
路由分发:
# 当APP增多时,不同的APP可能使用到相同的URL,这时如果都在urls.py中添加的话将照成冲突,我们就可以使用到Django的路由分发功能 # 在urls.py中添加 from django.urls import include urlpatterns = [ path('一类URL', include("APP名称.urls")), ] # 这时在对应APP目录下创建urls.py文件编写路由即可 e.g: from django.urls import include urlpatterns = [ path('cmdb/', include("cmdb.urls")), ] # 此时在浏览器访问host:port/cmdb/URL
path和re_path可加name参数,为该URL设置一个名称:
urlpatterns = [ path('URL', 视图函数, name='自定义名称'), re_path('URL', 视图函数, name='自定义名称'), ] # 在HTML中可以使用模板语言来调用该名称 {% url "自定义名称" 参数(随便填,xxx=如果有正则) %}
命名空间:
name参数没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定的URL时,立即返回,当不小心定义相同的name时,可能会导致URL反解错误,为了避免该错误发生,可使用命名空间
# 在urls.py中添加 from django.urls import include urlpatterns = [ path('一类URL', include("APP名称.urls"), namespace= "aaa"), ] # 在对应APP目录下创建的urls.py文件添加 from django.urls import path from xxx import views app_name = "xxx" urlpatterns = [ path('bbb/', views.xxx, name="index"), ] # 这时,使用反解得到的URL print(reverse("xxx:index")) # /aaabbb/
在Django中自动生成URL:
from django.urls import reverse reverse('URL', args=(n,...)) reverse('URL', kwargs={}) # 使用此方法生成的URL将带有后面第二个参数的内容
3.4、FBV与CBV
FBV即function、base、view,是URL与函数的对应,CBV即class、base、view,是URL与类的对应。
FBV路由编写:
urlpatterns = [ path('URL', 函数), ]
CBV路由编写:
urlpatterns = [ path('URL', 类.as_view()), ]
FBV函数编写:
def func(request): pass # request为客户端传入的所有请求
CBV中的类编写:
from django.views import View class Foo(View): def get(self, request): # 传入GET请求 pass def post(self, request): # 传入POST请求 pass
FBV与CBV使用装饰器:
# FBV使用装饰器与平时一样 # 装饰器xxx @xxx def func(request): pass # CBV使用装饰器时,需进行如下操作 from django.utils.decorators import method_decorator # 单个方法使用装饰器 class Obj(views.View): @method_decorator(xxx) def get(self, request): pass def post(self, request): pass @method_decorator(xxx, name="使用装饰器的方法") class Obj(views.View): def get(self, request): pass def post(self, request): pass # 整个类使用装饰器 @method_decorator(xxx, name="dispatch") class Obj(views.View): def get(self, request): pass def post(self, request): pass
3.5、视图函数
视图函数用于处理用户发送到服务端的请求,处理相应的业务,在相应APP目录下的views.py文件中编写。
def func(request): request.method # 用于判断客户端传入的请求类型,如GET、POST,值均为大写 request.GET/POST # 接收客户端相应请求类型下的数据,字典模式 request.POST.get() # 因为请求中的数据为字典类型,所以可以使用get取相应key的value,这里不推荐使用[],因为使用[]时若相应的key不存在则会报错 request.POST.getlist() # 用于获取返回值是多个数据,如checkbox的返回值 obj = request.FILES.get() # 上传文件时,生成一个实例 obj.name # 获取文件名 obj.size # 获取文件的字节数 obj.chunks # 获取文件的数据块,当文件上传时分为一个个数据块上传,可以循环该方法接收完整的文件数据,也可以直接循环obj,Django内部将调用chunks request.path_info # 获取当前URL # request在前端也可以拿到,可以通过模板语言使用
获取用户请求头及请求主体信息:
# 用户传入的请求包含请求头和请求主体信息,使用以下方法获取全部信息 from django.core.handlers.wsgi import WSGIRequest
request.environ # 将以字典形式返回所有的信息 # 直接获取未经过Django处理的原生请求数据 # 获取请求头 request.Meta # 获取请求主体 request.body # 以下方法属于请求头信息 request.method request.path_info request.COOKIES # 以下方法属于请求主体信息 request.GET requets.POST request.FILES
3.6、模板语言
Django的模板语言用于接收后台返回的数据并将数据嵌入HTML中。
{{ xxx }} # 用后台返回的内容替换HTML e.g: <span>{{ xxx }}</span>
模板语言中取列表和字典的值:
# 取列表值 list = [] list.下标 # 取字典的值 dict = {} dict.key
for循环:
{% for item in xxx %} ...... {% endfor %} # for循环中有以下几个方法 # forloop.counter,计数器 # forloop.revcounter,倒数计数器 # forloop.counter0,从0开始的计数器 # forloop.revcounter0,从0开始的倒数计数器 # forloop.first,是否第一个循环 # forloop.last,是否最后一个循环 # forloop.parentloop,父循环的以上6个信息
if语句:
{% if xxx %} ...... {% else %} ...... {% endif %}
使用模板语言循环字典:
# 循环字典的键 {% for item in dict.keys %} {% endfor %} # 循环字典的值 {% for item in dict.values %} {% endfor %} # 循环字典的键值对 {% for k, v in dict.items %} {% endfor %}
模板的继承:
# 创建模板HTML,通用部分写HTML,改变的部分如下: {% block 名称 %} {% endblock %} # 需要使用模板的其他HTML文件 {% extends "模板HTML" %} # 声明继承的模板 {% block 模板中的block名称 %} HTML代码... {% endblock %} # 注意,只能继承一个模板
导入模板组件:
可以将HTML页面中经常使用的部分设计成小组件,在其他页面需要使用的时候导入即可。
# 创建一个HTML文件,写HTML代码 # 需要引入时使用: {% include "HTML文件" %}
自定义simple_tag:
自定义simple_tag允许用户在模板语言中使用自己定义的Python函数,具体步骤如下,
1.在APP中创建templatetags目录(Python Package)
2.在目录中创建任意py文件
# 创建xxx.py文件 from django import template register = template.Library() @register.simple_tag def func(x1, x2, …): ...
3.在使用自定义simple_tag的HTML文件中导入之前创建的xxx.py
{% load xxx %}
4.使用自定义simple_tag
{% func 参数1 参数2 …%}
注意:使用自定义simple_tag之前必须在settings.py中的INSTALLED_APPS中注册该APP。
自定义filter:
自定义filter类似自定义simple_tag,具体步骤如下,
1.在APP中创建templatetags目录(Python Package)
2.在目录中创建任意py文件
# 创建xxx.py文件 from django import template register = template.Library() @register.filter def func(x1, x2): ...
3.在使用自定义filter的HTML文件中导入之前创建的xxx.py
{% load xxx %}
4.使用自定义filter
{{ 参数1|func:参数2 }} # 注意:函数的参数跟函数间不能有空格
自定义simple_tag与自定义filter的区别:
自定义simple_tag可以传入多个参数,但是不能作为if语句的条件;自定义filter只能传入两个参数,但是可以作为if语句的条件使用
3.7、为用户返回结果
Django有以下三种方式可以给用户返回最终结果
# 返回字符串 from django.shortcuts import HttpResponse return HttpResponse("字符串" or "字节") # 返回模板文件(HTML) from django.shortcuts import render return render(request, "模板文件路径", {字典,返回内容给模板语言}) # 返回一个URL from django.shortcuts import redirect return redirect("URL")
4、Cookie和Session
4.1、Cookie
Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie是由WEB服务器保存在用户浏览器上的一个小文件,通过类似字典的键值对方式存储有关用户的信息,无论何时用户连接到服务器,WEB站点都可以访问Cookie中的信息。
获取Cookie:
def func(request): request.COOKIES["xxx"] request.COOKIES.get("xxx")
设置Cookie:
def func(request): rep = HttpResponse or rep = render(request, xx.html) rep.set_cookie(key, value, ...) # 参数: # key --> 键 # value --> 值 # max_age= --> 超时时间,秒 # expires= --> 超时时间,具体日期 # path="/" --> Cookie生效的路劲,/表示根路径,根路径的Cookie可以被任何页面访问 # domain= --> Cookie生效的域名 # secure=True/False --> HTTPS传输 # httponly=True/False --> 只能HTTP协议传输,无法被JS获取
注意:不设置Cookie超时时间时,Cookie在关闭浏览器前均有效。
将Cookie失效时间设置为当前时间即可清除Cookie。
加密Cookie:
# 获取加密Cookie def func(request): request.get_signed_cookie(key, default=RAISE_ERROR,salt="加密盐", max_age=) # 设置加密Cookie def func(request): rep = HttpResponse() or rep = render(request, xx.html) rep.set_signed_cookie(key, value, salt="加密盐", ...)
注意:由于Cookie存储与客户端,所以在基于Cookie的用户认证中,为了安全不建议将敏感信息放置于Cookie中。
4.2、Session
Session,在计算机中,尤其是在网络应用中,被称为“会话控制”。Session对象存储特定用户会话过程中所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。
与Cookie相同的是,Session也是通过键值对的形式保存信息;而与Cookie不同的是,Session保存在服务器端而非客户端。但是Session必须与Cookie配合使用,Session会将该项生成的一段随机字符串保存在Cookie中,其他信息则保存在服务端。
在Django中,默认情况下Session保存在Django自带的数据库中,所以在使用Session前必须先进行创建数据库的操作。
Django中Session的使用:
def func(request): # 获取Session request.session["xxx"] request.session.get("xxx") # 设置Session request.session["xxx"] = xxx request.session.setdefault("xxx", xxx) # 不存在则设置 # 删除Session del request.session["xxx"] # 所有键、值、键值对操作 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # Session随机字符串 request.session.session_key() # 删除所有失效日期小于当前日期的Session request.session.clear_expired() # 检查用户Session随机字符串在数据库中是否存在 request.session.exists("session_key") # 删除当前用户所有的Session request.session.clear() request.session.delete("session_key") # 设置Session失效时间 request.session.set_expiry(value) # 参数: # value为整数 --> Session会在设置的秒数后失效 # value为datatime或timedelta --> Session会在这个时间后失效 # value为0 --> Session会在关闭浏览器时失效 # value为None --> Session依赖settings.py中设置的失效策略,默认为两周
settings.py中可配置Session默认行为:
# 引擎(默认) SESSION_ENGINE = 'django.contrib.sessions.backends.db' # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存的路径(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的域名(默认) SESSION_COOKIE_DOMAIN = None # 是否Https传输cookie(默认) SESSION_COOKIE_SECURE = False # 是否Session的cookie只支持http传输(默认) # Session的cookie失效日期(2周)(默认) SESSION_COOKIE_AGE = 1209600 # 是否关闭浏览器使得Session过期(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否每次请求都保存Session,默认修改之后才保存(默认) SESSION_SAVE_EVERY_REQUEST = False
Django中默认将Session保存在自带数据库的django_session表中,也可以将Session保存在其他地方,Django提供了以下5种类型供开发者使用:
- 数据库,默认保存位置
- 缓存
- 文件
- 缓存+数据库
- 加密Cookie
通过配置settings.py中的SESSION_ENGINE = “”即可修改保存方式
# 数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 缓存 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 # 文件 SESSION_ENGINE = 'django.contrib.sessions.backends.file' SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 缓存+数据库,数据库用于做持久化,缓存用于提高效率 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 加密Cookie SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
5、XSS和CSRF
5.1、XSS
XSS全称跨站脚本攻击,是一种在WEB应用中的计算机安全漏洞,它允许恶意WEB用户将代码(如HTML代码和JS脚本)植入到提供给其他用户使用的页面中。
为了防止XSS攻击,Django后台在返回给前台的数据中出现如HTML代码或JS脚本的字符串时,在前台将按字符串显示,而不会将代码解析未HTML或脚本。当我们需要将返回的代码或脚本实现功能而不已字符串显示时,可以使用如下方法:
# 后台Views函数 from django.shortcuts import HttpResponse from django.utils.safestring import mark_safe def func(request): xxx = "<a href='www.baidu.com'>百度一下</a>" xxx = mark_safe(xxx) return HttpResponse(xxx) # 前台HTML文件,使用模板语言 {{ xxx|safe }}
5.2、CSRF
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者“Session Riding”,是一种对网站的恶意利用。尽管听起来像跨站脚本XSS,但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
Django中的中间件django.middleware.csrf.CsrfViewMiddleware提供了全局防止CSRF攻击的功能,在Views函数中也可以设置局部防止CSRF攻击的功能。
全局防止CSRF:
启用中间件django.middleware.csrf.CsrfViewMiddleware
局部防止CSRF:
from django.views.decorators.csrf import csrf_exempt, csrf_protect # 当前函数设置防止CSRF攻击,即使中间件没有启用 @csrf_protect def func(request): ... # 当前函数取消防止CSRF攻击,即使中间件启用 @csrf_exempt def func(request): ...
前台设置csrf token
form表单:
<form> {% csrf_token %} </form>
Ajax:
csrf token也保存在cookie中,所以在Ajax提交数据时可以使用保存在cookie中的csrf token
1.单个Ajax设置
$.ajax({ headers:{"X-CSRFtoken": $.cookie('csrftoken')}, })
2.全局Ajax设置
$.ajaxSetup({ beforeSend: function(xhr, settings){ xhr.setRequestHeader("X-CSRFtoken", $.cookie("csrftoken")); } });
6、Django使用缓存
如果每次请求时都去数据库中进行相应的操作,在访问量大时,耗时必然会更加明显。对于这种状况最简单的解决方法既是使用缓存,将某个Views的返回值保存在内存或者缓存服务器中,当一定的时间内有用户访问时,直接从内存或缓存中读取数据返回给用户。
Django中提供了以下6种方式使用缓存:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache(python-memcached模块)
- Memcache(pylibmc模块)
缓存的配置也在settings.py中进行:
# 开发模式 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】) } } # 内存,将内容保存在内存的变量中 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', ... } } # 文件,将内容保存在文件中 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '文件路径', ... } } #数据库,将内容保存在数据库中 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': '表名', } } # Memcache(python-memcached模块),使用python-memcached模块连接Memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': 'Memcache服务器', # 同时连接多台Memcache服务器 'LOCATION': ['服务器1', '服务器2', ...] # 多台Memcache服务器权重设置 'LOCATION': [('服务器1', 10), ('服务器2', 11), ...] } } # Memcache(pylibmc模块),使用pylibmc模块连接Memcache CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': 'Memcache服务器', # 同时连接多台Memcache服务器 'LOCATION': ['服务器1', '服务器2', ...] # 多台Memcache服务器权重设置 'LOCATION': [('服务器1', 10), ('服务器2', 11), ...] } }
Django也可以使用Redis缓存,但必须依赖django-redis模块(使用pip安装):
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"max_connections": 100} "PASSWORD": "密码", } } }
7、信号
Django中提供了“信号调度”,即允许在某些动作发生时,执行一些特定的操作。
内置信号:
Model signals pre_init # django的modal执行其构造方法前,自动触发 post_init # django的modal执行其构造方法后,自动触发 pre_save # django的modal对象保存前,自动触发 post_save # django的modal对象保存后,自动触发 pre_delete # django的modal对象删除前,自动触发 post_delete # django的modal对象删除后,自动触发 m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发 class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发 Management signals pre_migrate # 执行migrate命令前,自动触发 post_migrate # 执行migrate命令后,自动触发 Request/response signals request_started # 请求到来前,自动触发 request_finished # 请求结束后,自动触发 got_request_exception # 请求异常后,自动触发 Test signals setting_changed # 使用test测试修改配置文件时,自动触发 template_rendered # 使用test测试渲染模板时,自动触发 Database Wrappers connection_created # 创建数据库连接时,自动触发
使用内置信号:
# 可以新建目录或py文件,然后在工程文件夹下的__init__.py中导入,这样在Django运行时就可以使信号生效 from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exception from django.db.models.signals import class_prepared from django.db.models.signals import pre_init, post_init from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_delete, post_delete from django.db.models.signals import m2m_changed from django.db.models.signals import pre_migrate, post_migrate from django.test.signals import setting_changed from django.test.signals import template_rendered from django.db.backends.signals import connection_created def callback(sender, **kwargs): pass 信号.connect(callback) # 也可以使用装饰器来运行信号 from django.dispatch import receiver @receiver(信号) def my_callback(sender, **kwargs): pass
自定义信号:
# 定义信号 import django.dispatch xxx = django.dispatch.Signal(providing_args=[参数1, 参数2, ...]) # 注册信号 def callback(sender, **kwargs): pass xxx.connect(callback) # 触发信号,由于内置信号的触发者已集成在Django中,所以会自动调用,而自定义信号则需要开发者在需要的位置触发 from 路径 import xxx xxx.send(sender='触发者', 参数1 = , 参数2 = , ...)