03-Python 框架 Django、DRF
Django、flask、tornado 框架的比较 ★★★★★
Django:大而全的框架。它的内部组件比较多,如 ORM、Admin、中间件、Form、ModelForm、Session、缓存、信号、CSRF 等,功能也都很完善。
flask:微型框架,内部组件就比较少了,但是有很多第三方组件来扩展它,比如 wtform(与 Django 的 modelform 类似,表单验证)、flask-sqlalchemy(操作数据库的)、flask-session、flask-migrate、flask-script、blinker 等,可扩展强,第三方组件丰富。所以对他本身来说有那种短小精悍的感觉。
tornado:异步非阻塞。是一个轻量级的 Web 框架,异步非阻塞+内置 WebSocket 功能。目标是通过一个线程处理N个并发请求(处理IO)。内部组件:内部自己实现 socket、路由系统、视图、模板、cookie、csrf。
Django 和 flask 对比:
他们都没有写 socket,所以他们都是利用第三方模块 wsgi,但是内部使用的 wsgi 也是有些不同的:Django 使用 wsgiref,而 flask 使用 werkzeug wsgi。
他们的请求管理不太一样:Django 是通过将请求封装成 request 对象,再通过参数传递,而 flask 是通过上下文管理机制。
WSGI、uwsgi 和 uWSGI 的区别 ★★★
WSGI:全称 Web Server Gateway Interface(Web服务器网关接口),是一种通用的接口标准或者接口协议。定义了 Web 服务器如何与 Python 应用程序进行交互,使得用 Python 写的 Web 应用程序可以和 Web 服务器对接起来。
- 以下模块实现了 WSGI 协议:
wsgiref,werkzurg,uWSGI。 - 这几个模块本质:编写 socket 服务端,用于监听请求,当有请求到来,则将请求数据进行封装,然后交给 web 框架处理。
 
- 以下模块实现了 WSGI 协议:
 uwsgi:同 WSGI 一样是一种通信协议,它是一个二进制协议,uwsgi 协议是一个 uWSGI服务器 自有的协议,它用于定义传输信息的类型。
uWSGI:uWSGI 是一种 web 服务器,是实现了 uwsgi 和 WSGI 两种协议的 Web 服务器,负责响应 Python 的 web 请求。
Django
简述 MVC 和 MTV ★★★★★
- MVC:model(数据库)、view(模块)、controller(视图,控制)
 - MTV:model(数据库)、tempalte(视图)、view(控制)
 
Django 请求的生命周期 ★★★★★
用户请求进来先走到 wsgiref  --> 然后将请求交给 Django 的中间件  --> 穿过 Django 中间件(方法是process_request)  --> 路由匹配  --> 路由匹配成功之后就执行相应的视图函数  --> 在视图函数中可以调用 ORM 做数据库操作  --> 再从模板路径将模板拿到  --> 然后在后台进行模板渲染  --> 模板渲染完成之后就变成一个字符串  --> 再把这个字符串经过所有中间件(方法:process_response)   --> 最后通过 wsgiref 封装返回给用户

列举 Django 的内置组件 ★★★
form 组件
- 对用户请求的数据进行校验
 - 生成HTML标签
 
信号
Django 的信号其实就是 Django 内部为开发者预留的一些自定制功能的钩子。
只要在某个信号中注册了函数,那么 Django 内部执行的过程中就会自动触发注册在信号中的函数。如
pre_init: Django 的 modal 执行其构造方法前,自动触发。post_init:Django 的 modal 执行其构造方法后,自动触发。pre_save: Django 的 modal 对象保存前,自动触发。post_save:Django 的 modal 对象保存后,自动触发。
场景:在数据库某些表中添加数据时,可以进行日志记录。
CSRF
目标:防止用户直接向服务端发起 POST 请求。对所有的 POST 请求做验证。
方案:发送 GET 请求时,服务器将 token 保存到 cookie、Form 表单中(隐藏的 input 标签),以后浏览器再发送请求时需要携带过来才行。
ContentType
ContentType 是 Django 的一个组件(app),为我们找到 Django 程序中所有 app 中的所有表并添加到记录中。
可以使用他再加上表中的两个字段实现:一张表和 N 张表创建 FK 关系。 - 字段:表名称 - 字段:数据行ID。
中间件
对所有的请求进行批量处理,在视图函数执行前后进行自定义操作。
应用:用户登录校验。
问题:为甚么不使用装饰器?
答案:如果不使用中间件,就需要给每个视图函数添加装饰器,太繁琐。
session
cookie 与 session 区别:
cookie 是保存在浏览器端的键值对,而 session 是保存的服务器端的键值对,但是依赖 cookie。(也可以不依赖 cookie,可以放在 url,或请求头但是 cookie 比较方便)
以登录为例,cookie 为通过登录成功后,设置明文的键值对,并将键值对发送客户端存,明文信息可能存在泄漏,不安全;session 则是生成随机字符串,发给用户,并写到浏览器的 cookie 中,同时服务器自己也会保存一份。
在登录验证时,cookie 验证:根据浏览器发送请求时附带的 cookie 的键值对进行判断,如果存在,则验证通过;session 验证:在请求用户的 cookie 中获取随机字符串,根据随机字符串在 session 中获取其对应的值进行验证。
cors 跨域(场景:前后端分离时,本地测试开发时使用)
首先说域的概念,协议(http/https)+ 域名或IP地址 + 端口号 共同构成了域,三者有一个不同,则为不同的域。
如果网站之间存在跨域,浏览器因为同源策略的限制,而决绝解析返回的数据。
解决:在服务端的响应数据中加上对应的响应头(Django 在中间件 process_response)。
缓存
常用的数据放在缓存里面,就不用走视图函数,请求进来通过所有的 process_request 之后,会到缓存里面查数据,有就直接拿,没有就走视图函数,注意:
- 执行完所有的 
process_request才去缓存取数据。 - 执行完所有的 
process_response才将数据放到缓存。 
关于缓存问题:
为什么放在最后一个
process_request才去缓存。
因为需要验证完用户的请求,才能返回数据。什么时候将数据放到缓存中。
第一次走中间件,缓存没有数据,会走视图函数,取数据库里面取数据,当走完process_response才将数据放到缓存里,
因为走process_response的时候可能给我们的响应加处理。为什么使用缓存。
将常用且不太频繁修改的数据放入缓存。以后用户再来访问,先去缓存查看是否存在,如果有就返回,否则,去数据库中获取并返回给用户(再加入到缓存,以便下次访问)。
Django 中间件的5个方法以及应用场景 ★★★★★
1  |  | 

简述什么是 FBV 和 CBV
1  |  | 
FBV 与 CBV 的区别:
没什么区别,因为他们的本质都是函数。CBV 的 .as_view() 返回的 view 函数,view 函数中调用类的 dispatch 方法,在 dispatch 方法中通过反射执行 get/post/delete/put 等方法。
非要说区别的话:CBV 比较简洁,GET/POST 等业务功能分别放在不同 get/post 函数中。FBV 自己做判断进行区分。
Django 的 request 对象是在什么时候创建的 ★★★
当 request 请求到达 Django 服务器时, Django 会建立一个包含请求元数据的 HttpRequest 对象。当 Django 加载对应的视图时, HttpRequest 对象将作为视图函数的第一个参数传递给视图。当执行完视图的代码之后,每个视图会返回一个 HttpResponse 对象。
具体代码是:请求走到 WSGIHandler 类的时候,执行 cell 方法,将 environ 封装成了 request。
1  |  | 
如何给 CBV 的程序添加装饰器
1  |  | 
ORM
列举 Django ORM 中的方法(QuerySet对象的所有方法) ★★★★★
1  |  | 
only 和 defer 的区别?
- only: 仅取某列数据。
 - defer:排除某列数据。
 
1  |  | 
select_related 和 prefetch_related 的区别
他俩都用于连表查询,减少SQL查询次数。
select_related主要针一对一和多对一关系进行优化,通过多表 join 关联查询,一次性获得所有数据,存放在内存中,但如果关联的表太多,会严重影响数据库性能。1
2
3
4
5
6
7
8
9
10def index(request):
obj = Book.objects.all().select_related("publisher")
return render(request, "index.html", locals())
# 举例
def select_related(self, *fields)
# 性能相关:表之间进行join连表操作,一次性获取关联的数据。
model.tb.objects.all().select_related()
model.tb.objects.all().select_related('外键字段')
model.tb.objects.all().select_related('外键字段__外键字段')prefetch_related是通过分表,先获取各个表的数据,存放在内存中,然后通过 Python 处理他们之间的关联。1
2
3
4
5
6
7
8
9
10
11
12
13
14def index(request):
obj = Book.objects.all().prefetch_related("publisher")
return render(request, "index.html", locals())
def prefetch_related(self, *lookups)
# 性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
# 获取所有用户表
# 获取用户类型表where id in (用户表中的查到的所有用户ID)
models.UserInfo.objects.prefetch_related('外键字段')
from django.db.models import Count, Case, When, IntegerField
Article.objects.annotate(numviews=Count(Case(When(readership__what_time__lt=treshold, then=1), output_field=CharField(),)))
students = Student.objects.all().annotate(num_excused_absences=models.Sum(models.Case(models.When(absence__type='Excused', then=1),default=0,output_field=models.IntegerField())))
1  |  | 
filter 和 exclude 的区别?
1  |  | 
列举 Django ORM 中三种能写 SQL 语句的方法
1  |  | 
Django ORM 中如何设置读写分离?
1  |  | 
F 和 Q 的作用 ★★★
F():主要用来获取原数据进行计算。Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
F查询专门对对象中某列值的操作,不可使用 __ 双下划线!
修改操作也可以使用F函数,比如将每件商品的价格都在原价格的基础上增加10。
1  |  | 
Q:用来进行复杂查询,Q查询可以组合使用 &、| 操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象,Q对象可以用 ~ 操作符放在前面表示否定,也可允许否定与不否定形式的组合。
Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
- Q(条件1) | Q(条件2):或
 - Q(条件1) & Q(条件2):且
 - Q(条件1) & ~Q(条件2):非
 
values 和 values_list 的区别?
1  |  | 
如何使用 Django ORM 批量创建数据?
1  |  | 
Django 的 Form 和 ModelForm 的作用?
作用:
- 对用户请求数据格式进行校验。
 - 自动生成HTML标签。
 
区别:
- Form,字段需要自己手写。
1
2
3
4
5class Form(Form):
xx = fields.CharField(.)
xx = fields.CharField(.)
xx = fields.CharField(.)
xx = fields.CharField(.) - ModelForm,可以通过 Meta 进行定义
1
2
3
4class MForm(ModelForm):
class Meta:
fields = "__all__"
model = UserInfo 
- Form,字段需要自己手写。
 应用:只要是客户端向服务端发送表单数据时,都可以进行使用,如:用户登录注册。
Django 的 Form 组件中,如果字段中包含choices参数,请使用两种方式实现数据源实时更新。
原因:choice 的数据如果从数据库获取可能会造成数据无法实时更新。
1  |  | 
Django 的 Model 中的 ForeignKey 字段中的 on_delete 参数有什么作用
在 Django2.0 后,定义外键和一对一关系的时候需要加 on_delete 选项,此参数为了避免两个表里的数据不一致问题,不然会报错:
TypeError: __init__() missing 1 required positional argument: 'on_delete'
举例说明:
1  |  | 
on_delete 有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值:
- CASCADE:此值设置,是级联删除。一般情况下使用CASCADE就可以了。
 - PROTECT:此值设置,是会报完整性错误。
 - SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
 - SET_DEFAULT:此值设置,会把设置为外键的默认值。
 - SET():此值设置,会调用外面的值,可以是一个函数。
 
解释 ORM 中 db first 和 code first 的含义?
- db first: 先创建数据库,再更新表模型。
 - code first:先写表模型,再更新数据库。
 - https://www.cnblogs.com/jassin-du/p/8988897.html。
 
Django 中如何根据数据库表生成 model 中的类?
- 修改 setting 文件,在 setting 里面设置要连接的数据库类型和名称、地址。
 - 运行 
python manage.py inspectdb可以自动生成models模型文件。 - 创建一个app执行 
python manage.py inspectdb > app/models.py命令。 
使用 ORM 和原生 sql 的优缺点
SQL:
- 优点:执行速度快。
 - 缺点:编写复杂,开发效率不高。
 
ORM:
- 优点:让用户不再写SQL语句,提高开发效率,可以很方便地引入数据缓存之类的附加功能。
 - 缺点:在处理多表联查、where 条件复杂查询时,ORM 的语法会变得复杂,没有原生 SQL 速度快。
 
Django 中如何实现 ORM 表中添加数据时创建一条日志记录
给信号注册函数,使用 Django 的信号机制,可以在添加、删除数据前后设置日志记录。
1  |  | 
Django 中 csrf 的实现机制 ★★★★★
目的:防止用户直接向服务端发起 POST 请求。
配置文件中开启 CSRF 中间件,然后在所有的 POST 表单模板中,加一个
{\%csrf_token%\}标签,它的功能其实是给 form 增加一个隐藏的 input 标签,<input type="hidden" name="csrfmiddlewaretoken" value="">
而这个csrf_token = cookie.csrftoken,在渲染模板时 context 中有context['csrf_token'] = request.COOKIES['csrftoken']。在用户访问 Django 的站点时,Django 会渲染该模板,并在页面中生成一个
csrftoken口令,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值。在通过表单发送 POST 到服务器时,表单中包含了上面隐藏了
crsrmiddlewaretoken这个 input 项,服务端收到后,Django 会验证这个请求的 cookie 里的 csrftoken 字段的值和提交的表单里的 csrfmiddlewaretoken 字段的值是否一样。
如果一样,则表明这是一个合法的请求,否则,这个请求可能是来自于别人的 csrf 攻击,返回 403 Forbidden。如果使用 ajax 发送 POST 请求到服务器时,要求 header 增加一个
x-csrftoken,其值为 cookie 里的 csrftoken 的值,服务湍收到后 Django 会验证这个请求的 cookie 里的 csrftoken 字段与 ajax post消息头中的x-csrftoken是否相同,如果相同,则表明是一个合法的请求。
在中间件的 process_view 方法中进行校验
基于 Django 使用 ajax 发送 post 请求时,都可以使用哪种方法携带 csrf_token?
1  |  | 
Django 如何实现 websocket
Django 可以通过 channel 实现 websocket。
Django 缓存
Django 中提供了 6 种缓存方式:
- 开发调试(不加缓存)
 - 内存
 - 文件
 - 数据库
 - Memcache 缓存(python-memcached模块)
 - Memcache 缓存(pylibmc模块)
 - 安装第三方组件支持 Redis:django-redis组件
 
设置缓存
1  |  | 
Django 的缓存能使用 Redis 吗?如果可以的话,如何配置
1  |  | 
Django 路由系统中 name 的作用
路由系统中 name 的作用:反向解析路由字符串。
- 路由:
url(r'^home', views.home, name='home') - 在模板中使用:
1
{% url 'home' %} - 在视图中使用:
reverse("home") 
Django 的模板中 filter 和 simple_tag 的区别
filter: 类似管道,只能接受两个参数,第一个参数是|前的数据。simple_tag: 类似函数。
- 模板继承:
1
{% extends 'layouts.html' %} - 自定义方法
filter:只能传递两个参数,可以在if、for语句中使用。simple_tag:可以无线传参,不能在if for中使用。inclusion_tags:可以使用模板和后端数据。
 - 防 xss 攻击: 
|safe、mark_safe 
django-debug-toolbar的作用?
- 查看访问的速度、数据库的行为、cache命中等信息。
 - 尤其在 Mysql 访问等的分析上大有用处(sql查询速度)。
 
Django 中如何实现单元测试
对于每一个测试方法都会将 setUp() 和 tearDown() 方法执行一遍。
会单独新建一个测试数据库来进行数据库的操作方面的测试,默认在测试完成后销毁。
在测试方法中对数据库进行增删操作,最后都会被清除。也就是说,在 test_add 中插入的数据,在 test_add 测试结束后插入的数据会被清除。
Django 单元测试时为了模拟生产环境,会修改 settings 中的变量,例如, 把 DEBUG 变量修改为 True, 把 ALLOWED_HOSTS 修改为 [*]。
Django 的 contenttype 组件的作用
contenttype 是 Django 的一个组件(app),它可以将 Django 下所有 app 下的表记录下来。
可以使用他再加上表中的两个字段,实现一张表和 N 张表动态创建 FK 关系。
- 字段:表名称
 - 字段:数据行ID
 - 应用:一个策略表,同时关联不同的告警事件表
 
RESTful
谈谈你对 RESTful 规范的认识
RESTful 其实就是一套编写接口的’协议’,规定如何编写以及如何设置返回值、状态码等信息。
- 用 RESTful: 给用户一个 url,根据 method 不同在后端做不同的处理。比如:post创建数据、get获取数据、put和patch修改数据、delete删除数据。
 - 不用 RESTful: 给调用者很多 url,每个 url 代表一个功能,比如:
add_user/delte_user/edit_user/ 
规范:
- 使用 HTTPS 协议。
 - 域名体现是 API。
 - 体现版本。’版本’来控制让程序有多个版本共存的情况,版本可以放在 url、请求头(accept/自定义)、GET参数。
 - 路径,网络上任何东西都是资源,均使用名词表示(可复数)面向资源编程,RESTful 也可以称为“面向资源编程”。
 - 根据 method 不同,进行不同操作。
- GET :从服务器取出资源(一项或多项)
 - POST :在服务器新建一个资源
 - PUT :在服务器更新资源(客户端提供改变后的完整资源)
 - PATCH :在服务器更新资源(客户端提供改变的属性)
 - DELETE :从服务器删除资源
 
 - 通过在 url 上传参的形式传递搜索条件
 - 响应式设置状态码
1
2
3
4
5
6
7
8
9
10
11
12200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功 - 状态码是 4xx 时,应返回错误信息,error 当做 key。
 - 针对不同操作,服务器向用户返回的结果应该符合以下规范
1
2
3
4
5GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象;获取单条数据
POST /collection:返回新生成的资源对象;返回新增的数据
PUT /collection/resource:返回完整的资源对象;更新
PATCH /collection/resource:返回完整的资源对象;局部更新 - Hypermedia API: RESTful API 最好做到 Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
 
接口的幂等性是什么意思
接口的幂等性指的是对于同一接口的多次请求,其结果应保持一致,即不会因为请求的多次执行而产生不同的结果或副作用。
一个幂等操作满足以下条件:
- 多次执行相同操作,产生的效果与执行一次相同操作的效果相同。
 - 重复执行相同请求的结果与第一次执行该请求的结果相同。
 
- GET # 多次也是获取结果对资源都不会造成影响,幂等。
 - POST # 多次请求会多次新增,不是幂等。
 - PUT # 如果是绝对值更新,是幂等的。如果是增量的更新,不是幂等。
 - PATCH # 如果是绝对值更新,是幂等的。如果是增量的更新,不是幂等。
 - DELTE # 根据唯一值删除数据,是幂等。
 
DRF(Django rest framework)
为什么要使用 Django rest framework 框架
在编写接口时可以不使用 Django rest framework 框架。
- 不使用:也可以做,可以用 Django 的 CBV 来实现,开发者编写的代码会更多一些。
 - 使用:内部帮助我们提供了很多方便的组件,我们通过配置就可以完成相应操作。
 
Django rest framework 框架中都有那些组件
1  |  | 
Django rest framework 框架中的视图都可以继承哪些类
1  |  | 

简述 Django rest framework 框架的认证流程
源码流程:请求进来先走 dispatch 方法,然后封装的 request 对象会执行 user 方法,由 user 触发 authenticators 认证流程。
如何编写类并实现 authenticators?
认证需要编写一个类,类里面有一个 authenticators 方法,我们可以自定义这个方法,可以定制3类返回值。
- (user,auth),认证成功
 - None, 匿名用户
 - 异常,认证失败
 
Django rest framework 如何实现的用户访问频率控制 ★★★
1  |  | 
如何封IP:在防火墙中进行设置
Tornado
简述 Tornado 框架的特点。
异步非阻塞+websocket
简述 Tornado 框架中 Future 对象的作用?
实现异步非阻塞。
视图函数 yield 一个 futrue 对象,futrue 对象默认:
    self._done = False   ,请求未完成
    self._result = None  ,请求完成后返回值,用于传递给回调函数使用。
tornado 就会一直去检测 futrue 对象的 _done 是否已经变成 True。
如果IO请求执行完毕,自动会调用 future 的 set_result 方法:
    self._result = result
    self._done = True
参考:http://www.cnblogs.com/wupeiqi/p/6536518.html(自定义异步非阻塞web框架)
Tornado 框架中如何编写 WebSocket 程序
Tornado 在 websocket 模块中提供了一个 WebSocketHandler 类。这个类提供了和已连接的客户端通信的 WebSocket 事件和方法的钩子。
当一个新的 WebSocket 连接打开时,open 方法被调用,而 on_message 和 on_close 方法,分别在连接、接收到新的消息和客户端关闭时被调用。
此外,WebSocketHandler 类还提供了 write_message 方法用于向客户端发送消息,close方法用于关闭连接。
### Tornado 中静态文件是如何处理的?
如:<link href="{\{ static_url("commons.css") }\}" rel="stylesheet" />
1  |  | 
Tornado 操作 MySQL 使用的模块
torndb: torndb 是基于 mysqldb 的再封装,所以使用时要先安装 myqldb
Tornado 操作 redis 使用的模块
tornado-redis
简述 Tornado 框架的适用场景
web聊天室,在线投票