本文转载自:博客园@ 申不二
博客地址:https://www.cnblogs.com/shenbuer/p/7683343.html
感谢分享。
目录
一、wsgi接口
二、中间件
三、URL路由系统
四、Template模板
五、Views视图
六、Model&ORM
七、Admin相关
八、Http协议
九、COOKIE 与 SESSION
十、Django的用户认证
十一、From与ModelForm
十二、分页
十三、缓存
十四、信号
十五、序列化
十六、Ajax
十七、数据库性能相关
0、Django的生命周期
一、wsgi接口
了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:
-
浏览器发送一个HTTP请求;
-
服务器收到请求,生成一个HTML文档;
-
服务器把HTML文档作为HTTP响应的Body发送给浏览器;
-
浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。
如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。
正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。
这个接口就是WSGI:Web Server Gateway Interface。
WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello, web!”:
1
2
3
|
def application(environ, start_response): start_response( '200 OK' , [( 'Content-Type' , 'text/html' )]) return '<h1>Hello, web!</h1>' |
上面的application()
函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:
-
environ:一个包含所有HTTP请求信息的
dict
对象; -
start_response:一个发送HTTP响应的函数。
在application()
函数中,调用:
1
|
start_response( '200 OK' , [( 'Content-Type' , 'text/html' )]) |
就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()
函数。start_response()
函数接收两个参数,一个是HTTP响应码,一个是一组list
表示的HTTP Header,每个Header用一个包含两个str
的tuple
表示。
通常情况下,都应该把Content-Type
头发送给浏览器。其他很多常用的HTTP Header也应该发送。
然后,函数的返回值'<h1>Hello, web!</h1>'
将作为HTTP响应的Body发送给浏览器。
有了WSGI,我们关心的就是如何从environ
这个dict
对象拿到HTTP请求信息,然后构造HTML,通过start_response()
发送Header,最后返回Body。
整个application()
函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。
不过,等等,这个application()
函数怎么调用?如果我们自己调用,两个参数environ
和start_response
我们没法提供,返回的str
也没法发给浏览器。
所以application()
函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。但是现在,我们只想尽快测试一下我们编写的application()
函数真的可以把HTML输出到浏览器,所以,要赶紧找一个最简单的WSGI服务器,把我们的Web应用程序跑起来。
好消息是Python内置了一个WSGI服务器,这个模块叫wsgiref,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。
运行WSGI服务
我们先编写hello.py
,实现Web应用程序的WSGI处理函数:
1
2
3
4
5
|
# hello.py def application(environ, start_response): start_response( '200 OK' , [( 'Content-Type' , 'text/html' )]) return '<h1>Hello, web!</h1>' |
然后,再编写一个server.py
,负责启动WSGI服务器,加载application()
函数:
1
2
3
4
5
6
7
8
9
10
11
|
# server.py # 从wsgiref模块导入: from wsgiref.simple_server import make_server # 导入我们自己编写的application函数: from hello import application # 创建一个服务器,IP地址为空,端口是8000,处理函数是application: httpd = make_server( '' , 8000, application) print ( "Serving HTTP on port 8000..." ) # 开始监听HTTP请求: httpd.serve_forever() |
确保以上两个文件在同一个目录下,然后在命令行输入python server.py
来启动WSGI服务器:
注意:如果8000
端口已被其他程序占用,启动将失败,请修改成其他端口。
启动成功后,打开浏览器,输入http://localhost:8000/
,就可以看到结果了:
二、中间件
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件
中间件中一共有五个方法:
process_request - 有,直接执行当前中间件和上方中间件的process_response - 应用: 用户登录授权(排除不需要登录的url) process_view process_exception - process_tempalte_response - 必须有返回值 - 必须对象中要有render方法 process_response - 必须有返回值
中间件之process_request,process_response
process_request(self,request)
process_response(self, request, response)
当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者
在django中叫中间件,在其他web框架中,有的叫管道,httphandle
中间件之process_view执行过程:
当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户
中间件之process_exception
process_exception(self, request, exception)
当views的函数中出现错误时,就会执行process_exception方法
如果在中间中添加了process_exception方法,工作图示为:
这样当用户发起请求的时候到达中间件3的process_request之后会到达urls路由关系映射这里,如果匹配到了就会到中间件1的process_view,然后依次传递到中间件3的process_view,到达view函数。如果view函数中有报错,则会从中间件3依次向上判断每个中间件的process_exception是否能匹配到这个错误信息,如果匹配到则直接返回到最后一个中间件,这里即中间件3的process_response,然后依次返回到用户,如果没有匹配到这个错误则直接在页面显示错误信息。如果view函数中没有错误,则到中间3即最后一个中间件3的process_response,然后依次向上,传到用户
中间件之process_template_responseprocess
process_template_response(self,request,response)
只有当views函数中返回的对象中具有render方法,是就会直接process_template_responseprocess
中间件的应用
所有请求统一做处理时使用
- 登录验证
-添加访问日志等
自定义中间件
上述图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin
所以需要导入:from django.utils.deprecation import MiddlewareMixin
我们在项目文件下创建一个Middle目录,并在下面创建m1.py代码例子如下
配置settings.py
三、URL路由系统(URLconf)
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
3.1 简单配置
3.2 有名分组(named group)
上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。
在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern)
,其中name
是组的名称,pattern
是要匹配的模式。
下面是以上URLconf 使用命名组的重写:
这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。例如:
在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序。当然,这些好处是以简洁为代价;有些开发人员认为命名组语法丑陋而繁琐。
3.3 URLconf 在什么上查找
URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。
例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/
。
在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/
。
URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST
、GET
、HEAD
等等 —— 都将路由到相同的函数。
3.4 捕获的参数永远是字符串
每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
views.year_archive()
的year
参数将是一个字符串
3.5 指定视图参数的默认值
有一个方便的小技巧是指定视图参数的默认值。 下面是一个URLconf 和视图的示例
在上面的例子中,两个URL模式指向同一个视图views.page
—— 但是第一个模式不会从URL 中捕获任何值。如果第一个模式匹配,page()
函数将使用num
参数的默认值"1"。如果第二个模式匹配,page()
将使用正则表达式捕获的num
值。
3.1.6 路由分发( Including other URLconfs)
在项目中,若需要将某一应用下url统一跳转,则可以使用 Including other URLconfs
四、Template模板
python的模板:HTML代码+逻辑控制代码
4.1 模板支持的语法
4.1.1 变量(使用双大括号来引用变量)
语法格式: {{var_name}}
Django 模板解析非常快捷。 大部分的解析工作都是在后台通过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎形成鲜明对比,那些引擎承担了 XML 解析器的开销,且往往比 Django 模板渲染引擎要慢上几个数量级。
4.1.2 深度变量的查找(万能的句点号)
在到目前为止的例子中,我们通过 context 传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。
4.1.3 变量的过滤器(filter)的使用
4.1.4自定义filter和simple_tag
a、在app中创建templatetags模块(必须的)
b、创建任意 .py 文件,如:my_tags.py
c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}
d、使用simple_tag和filter(如何调用)
e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
注意:
filter可以用在if等语句后,simple_tag不可以
4.2 标签(tag)的使用(使用大括号和百分比的组合来表示使用tag)
语法格式: {% tags %}
{% if %} 的使用
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容
{% for %}的使用
{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
csrf_token标签
用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
{% url %}
引用路由配置的地址
{% with %}
用更简单的变量名替代复杂的变量名
4.3 extend模板继承
步骤:
a、新建 base.html,放在template目录下
b、使用模板标签: {% block %}分块,用于子模板继承
c、子模版集成(即重载block块)
继承的常见三层法:
模板继承的一些诀窍
五、Views视图
django中请求处理方式有2种:FBV 和 CBV
5.1 CBV(class base views)
CBV(class base views) 就是在视图里使用类处理请求。
5.1.1. 基本使用
使用方法为:urls.py 修改为如下:
views.py 修改为如下:
5.1.2. 基于dispatch和继承实现用户登录代码
1、写一个登录验证类
2、修改views.py并继承验证
5.1.3. 装饰器
1、get,post方法上,给任意函数添加
2、dispatch方法上,同时给get、post添加装饰器
3、类上
4、特殊:CSRF Token只能加到dispatch
5.2 FBV(function base views)
FBV(function base views) 就是在视图里使用函数处理请求。
5.2.1. 基本使用
1、使用方法为:urls.py 修改为如下:
2、views.py 修改为如下:
3、index.html
5.2.2快捷函数
render函数
redirect函数
六、Model&ORM
6.1、创建表
1、基本结构
2、连表结构
- 一对多:models.ForeignKey(其他表)
- 多对多:models.ManyToManyField(其他表)
- 一对一:models.OneToOneField(其他表)
6.2、操作表
1、基本操作
2、查询相关API
3、进阶操作(了不起的双下划线)
利用双下划线将字段和对应的操作连接起来
4、连表操作(了不起的双下划线)
利用双下划线和 _set 将表之间的操作连接起来
5、聚合查询和分组查询
<1> aggregate(*args,**kwargs):
通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
<2> annotate(*args,**kwargs):
可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
6、F查询和Q查询
七、Admin相关
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
- 创建后台管理员
- 配置url
- 注册和配置django admin后台管理页面
1、创建后台管理员
1
|
python manage.py createsuperuser |
2、配置后台管理url
1
|
url(r '^admin/' , include(admin.site.urls)) |
3、注册和配置django admin 后台管理页面
a、在admin中执行如下配置
b、设置数据表名称
c、一些常用的设置技巧(在admin.py文件中配置)
d、打开表之后,设定默认显示,需要在model中作如下配置(在admin.py文件中配置)
e、为数据表添加搜索功能(在admin.py文件中配置)
f、添加快速过滤(在admin.py文件中配置)
八、Http协议
8.1 HTTP概述
HTTP(hypertext transport protocol),即超文本传输协议。这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。
HTTP就是一个通信规则,通信规则规定了客户端发送给服务器的内容格式,也规定了服务器发送给客户端的内容格式。其实我们要学习的就是这个两个格式!客户端发送给服务器的格式叫“请求协议”;服务器发送给客户端的格式叫“响应协议”。
特点:
- HTTP叫超文本传输协议,基于请求/响应模式的!
- HTTP是无状态协议。
URL:统一资源定位符,就是一个网址:协议名://域名:端口/路径,例如:http://www.oldboy.cn:80/index.html
8.2 请求协议
请求协议的格式如下:
浏览器发送给服务器的内容就这个格式的,如果不是这个格式服务器将无法解读!在HTTP协议中,请求有很多请求方法,其中最为常用的就是GET和POST。
8.2.1 GET请求
HTTP默认的请求方法就是GET
1
2
3
|
* 没有请求体 * 数据必须在1K之内! * GET请求数据会暴露在浏览器的地址栏中 |
GET请求常用的操作:
8.2.2 POST请求
8.3 接收自定义http头部(headers)
用Python的httplib库来做模拟客户端,参考网上写出模拟代码如下:
其中'/headinfo/'为服务器的响应目录。
然后是服务端的响应代码,一个能够返回客户端自定义头部的模块
结果:
注意点:自定义请求头时,Django自动在头部META字典中的key值都会被加上“HTTP_”的前缀,category会变成 HTTP_CATEGORY ,auth-api 会变成 HTTP_AUTH_API
8.4 http请求request详解
8.5 HttpRequest 的方法
九、COOKIE 与 SESSION
9.1简介
9.2认证机制
9.3认证应用
第一步: 先在templates目录下创建两个html,login.html负责登录页面。backend页面代表后台页面
第二步:编辑app01应用下的views.py文件,编写代码逻辑部分
第三步,编辑mydjango目录下的urls.py文件。设置函数与页面的绑定关系
最后打开浏览器直接访问/backend/页面的时候直接就被重定向到了/login/
总结
9.4cookie知识点:
9.5session知识点:
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
1、数据库Session(默认)
2、缓存Session
3、文件Session
4、缓存+数据库Session
5、加密cookie Session
扩展:Session用户验证
十、Django的用户认证
10.1认证登录
1
|
from django.contrib import auth |
django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
10.1.1 authenticate()
10.1.2 login(HttpRequest, user)
10.1.3 logout(request) 注销用户
10.1.4 user对象的 is_authenticated()
要求:
1
2
3
|
1 用户登陆后才能访问某些页面, 2 如果用户没有登录就访问该页面的话直接跳到登录页面 3 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址 |
方法1:
1
2
3
|
def my_view(request): if not request.user.is_authenticated(): return redirect( '%s?next=%s' % (settings.LOGIN_URL, request.path)) |
方法2:login_required函数
django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()
1
2
3
4
5
|
from django.contrib.auth.decorators import login_required @login_required def my_view(request): ... |
若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递 当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
+++++++++++++++++++
10.2 User对象
User 对象属性:username, password(必填项)password用哈希算法保存到数据库
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否允许用户登录, 设置为``False``,可以不用删除用户来禁止 用户登录
10.3 User 对象方法
10.3.1 is_authenticated()
如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name
10.3.2 创建用户
10.3.3 set_password(passwd)
10.3.4 check_password(passwd)
1
|
用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True |
10.3.5 修改密码
示例:注册
示例:改密码
十一、Form与ModelForm
11.1 From
Django会将表单的提交变得更加简单和安全,包括重构数据后在页面间传递,创建前端的HTML页面以及接收和处理客户端传来的数据。实施上,你只需要事先定义好form表单的各种属性,在前端页面简单调用即可。当然,Django为Form提供了许多属性,方便自定义,甚至你可以重写其中的一些方法。
应用:使用注册表完成验证并注册
1、urls.py
2、models.py
3、在app 目录下新建 form.py
4、views.py
5、register.html
11.2 ModelForm
11.2.1ModelForm参数和使用
11.2.2 通过ModelForm完成三张表格的数据新增:
1) 在app01目录下建立forms.py文件,今后将所有的form都写在这个文件中,这个文件需要在views.py中导入,方便导入相应的FORM
2) 创建ModelForm:
forms.py:
建立url与view的关联关系
1
|
url(r '^add/' , echo.views.add), |
在views.py中建立相应的函数
views.py:
在templates文件夹下建立HTML文件,add.html
add.html:
十二、分页
12.1分页器的使用
12.2实现一个分页效果
index.html
views.py
十三、缓存
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
1、配置
a、开发调试
b、内存
c、文件
d、数据库
e、Memcache缓存(python-memcached模块)
f、Memcache缓存(pylibmc模块)
2、应用
a. 全站使用
b. 单独视图缓存
c、局部视图使用
十四、信号
Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。
1、Django内置信号
对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:
2、自定义信号
a. 定义信号
b. 注册信号
c. 触发信号
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。
十五、序列化
序列化
在django中,在将数据库中检索的数据返回给客户端用户,数据类型为QuerySet格式,而QuerySet格式不能被json格式化处理传到前端,因此在处理此类数据时有两种方法:
方法一:使用django自带的系列化模块 serializers模块
1、serializers
注:1、serializers序列化后的数据格式为列表,列表为每一个查询记录
2、serializers模块不能跨表查询,涉及一对多查询时,只能查询到关联字段
方法二:查询时转换为QuerySet字典或列表格式
2、json.dumps
特殊的:
SQLServer中使用索引视图(物化视图)
Github for Windows使用介绍
微软一站式示例代码库
SQL中存储过程中使用事务,并且加入异常处理机制.
.NET 性能分析工具
公众号和app和web都是客户端,都可以对接一个后台
服务器session,Tomcat有自己的session维护机制,apache有自己的session维护机制
主账户经验
spring mvc中的@propertysource