django-restframework

一、安装与使用

1.安装

>: pip3 install djangorestframework

2.使用

  • 在settings.py中注册:

    INSTALLED_APPS = [
    ....
    'api.apps.ApiConfig',
    # drf必须注册
    'rest_framework',
    ]
  • 模块

    # drf的封装风格
    from rest_framework.views import APIView # CBV
    from rest_framework.response import Response # 响应
    from rest_framework.request import Request # 请求
    from rest_framework.filters import SearchFilter # 过滤器
    from rest_framework.pagination import PageNumberPagination # 分页
    from rest_framework.exceptions import APIException # 异常
    from rest_framework.authentication import BaseAuthentication # 验证
    from rest_framework.permissions import IsAuthenticated # 组件
    from rest_framework.throttling import SimpleRateThrottle #
    from rest_framework.settings import APISettings # rest_framework配置文件
    from rest_framework import status # 状态码 from django.http.request import QueryDict # 类型
  • 基于CBV完成满足RSSTful规范接口

二、request请求分析

2.1. request数据请求

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.http.request import QueryDict
class BookAPIView(APIView): def get(self, request, *args, **kwargs):
print(request._request.GET) # 原生wigs中值
print(request.GET) # 二次封装的值
print(request.META) # 所有get请求信息
print(request.META.get("HTTP_AUTH")) # 前台发来的头都会大写并加上HTTP
print(request.query_params) # 所有url数据 print(request.POST) # get请求不能获取Post请求数据 return Response('get ok') def post(self, request, *args, **kwargs):
print(request._request.POST) # 原生wigs中值
print(request.POST) # 二次封装的值
print(request.data) # 所有post请求数据
print(request._request) # url数据包<WSGIRequest: POST '/books/?age=123'>
print(request.GET) # POST请求可以Post请求数据 # QueryDict转为
print(request.query_params.dict())
if isinstance(request.data, QueryDict):
print(request.data.dict()) return Response('post ok') # urls.py
from . import views
urlpatterns = [
url(r'^books/$', views.BookAPIView.as_view()),
]

总结:

  1. drf中的request是在wsgi的request基础上进行再一次封装
  2. 将wsgi的request作为drf的request的一个属性, _request
  3. drf中的request对wsgi中的request做完全兼容,新的可以直接获取wsgi中的数据
  4. drf中的request对数据解析更规范化,所有的拼接参数(url?age=18)都解析到了query_params中,所有数据报数据都解析到data中
  5. query_params和data属于QueryDict类型,可以通过.dict()转化为字典类型

2.2 request请求源码分析

# 1. 2. urls.py
from . import views
urlpatterns = [
url(r'^books/$', views.BookAPIView.as_view()),
] #3.调用drf中的as_view
@classmethod
def as_view(cls, **initkwargs): # cls 为 views.BookAPIView类
...
view = super().as_view(**initkwargs) # as_view原生的as_view,super() 为 view
view.cls = cls
view.initkwargs = initkwargs return csrf_exempt(view)
# 4.进入dif中dispatch
def dispatch(self, request, *args, **kwargs): # self为views.BookAPIView类
self.args = args
self.kwargs = kwargs
# 对原生request进行了二次封装
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response # 4.1 返回封装的request对象
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request) # 解析 return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# 5.Request类创建 self._request = request自己的属性
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
assert isinstance(request, HttpRequest), ( .format(request.__class__.__module__, request.__class__.__name__)
) self._request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context #6.如何实现获取wgis中的属性
def __getattr__(self, attr):
"""
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)

  1. 导入drf中的APIView并创建类继承它,在配置url: url(r'^books/$', views.BookAPIView.as_view()),
  2. 当项目启动时会执行drf中的as_view()方法,返回view方法(局部禁用了csrf认证), url:url(r'^books/$', views.BookAPIView.view
  3. 浏览器发送请求来时则会执行url中view函数,在执行view中返回的是 self.dispatch(request, *args, **kwargs), dispatch是drf中的dispatch, 不是wsgi中原生的dispatch
  4. 进入drf中的dispatch首先会对原生的request进行二次封装:request = self.initialize_request(request, *args, **kwargs),在initialize_request方法中返回了一个request实例对象
  5. 进入request.py中的Request方法中就会发现在初始化方法中将wsgi方法的request变为了自己的一个属性: 'self._request = request'
  6. request通过反射的方法获取wsgi中request属性,当request.获取属性先到 _request中查找,没有则查自己本身的
  7. 核心
    • 走drf的Request初始化方法__init__:self._request = request
    • drf的Request的getter方法__getattr__:先从self._request反射取属性,没取到再从drf的request中取

三、渲染模板

根据用户请求的RUL向服务器要响应的数据类型,比如:json数据,xml数据,将这些数据向用户返回

3.1渲染模板的使用

# 在renderers.py模板模块中导入你要渲染的模板
# JSONRenderer: 返回json数据
# BrowsableAPIRenderer: 返回浏览器html页面 from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer # 1.局部配置
# 渲染模块的局部配置
# 局部禁用就是配置空list:[] # pytthon3.7 有问题
renderer_classes = [JSONRenderer, BrowsableAPIRenderer] # 2.全局配置
# drf的配置,在drf中settings.py查看如何配置
REST_FRAMEWORK = {
# 渲染模块的全局配置:开发一般只配置json
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.TemplateHTMLRenderer',
], }

3.2渲染模板的源码解析

# 1 对请求响应进行二次封装
def dispatch(self, request, *args, **kwargs):
....
....
# 二次处理响应
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response # 2. 接续配置的渲染类
def finalize_response(self, request, response, *args, **kwargs): if isinstance(response, Response):
if not getattr(request, 'accepted_renderer', None):
# 点进去,内部解析了配置的渲染的类
neg = self.perform_content_negotiation(request, force=True)
# 拿到渲染类对象
request.accepted_renderer, request.accepted_media_type = neg response.accepted_renderer = request.accepted_renderer
response.accepted_media_type = request.accepted_media_type
response.renderer_context = self.get_renderer_context() # 3. 获取渲染对象的类
def perform_content_negotiation(self, request, force=False):
"""
Determine which renderer and media type to use render the response.
"""
# 点进去,获取配置的渲染类
renderers = self.get_renderers()
conneg = self.get_content_negotiator()
try:
return conneg.select_renderer(request, renderers, self.format_kwarg)
except Exception:
if force:
return (renderers[0], renderers[0].media_type)
raise # 3 renderer_classes 自己全局
def get_renderers(self):
"""
Instantiates and returns the list of renderers that this view can use.
"""
# 从自己的视图类找renderer_classer类属性(局部配置)APIView的类属性(从自己配置文件中找)> 自己的项目配置文件中找(全局配置), drf默认配置问价中找(默认配置)
return [renderer() for renderer in self.renderer_classes] class BaseRenderer:
"""
All renderers should extend this class, setting the `media_type`
and `format` attributes, and override the `.render()` method.
"""
media_type = None
format = None
charset = 'utf-8'
render_style = 'text' def render(self, data, accepted_media_type=None, renderer_context=None):
raise NotImplementedError('Renderer class requires .render() to be implemented')

总结:

  1. 根据流程,再次进入drf的dispatch方法,该方法对响应数据进行了二次封装,然后,进入self.finalize_response方法
  2. 在self.finalize_respons方法中perform_content_negotiation中获取渲染的对象结果,进入perform_content_negotiation方法
  3. perform_content_negotiation方法中实现了获取配置文件的渲染结果集,通过self.get_renderers()方法
  4. 在self.get_renderers()方法中self.renderer_classes读取配置的渲染对象,先从创建的视图类中(BookAPIView(APIView)(局部配置))找,然后在从自己的项目文件中找(项目中 settings.py,全局配置), 最后从drf默认配置文件中(默认配置)
  5. renderer()是从配置文件中获取到的对应类然后到 renderer.py 文件中获取类对象,创建的类对象(JSONRenderer())

四、解析模块的使用

服务器根据设置的请求头content-type接收客户端对应的数据信息

# JSONParser: 只接收json数据
# FormParser: 只接收urlencoded
# MultiPartParser:只接收form-data
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser # 1.局部配置
# 解析模块的局部配置
#局部配置禁用就是配置空list[]
parser_classes = [JSONParser, MultiPartParser, FormParser] # 2.全局配置
# drf的配置,在drf中settings.py查看如何配置
REST_FRAMEWORK = {
# 解析模块的全局配置
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser'
]
}

# 1.对数据进行二次解析
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
# 对原生request进行了二次封装,查看解析
request = self.initialize_request(request, *args, **kwargs)
... # 2 获取解析数据
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
# 准备要解析的字典
parser_context = self.get_parser_context(request) return Request(
# 初始wigs中request
request,
# 解析模块在封装原生request是,将数据一并解析
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context # 解析的内容
) # 2.1 返回要解析内容字典
def get_parser_context(self, http_request):
"""
Returns a dict that is passed through to Parser.parse(),
as the `parser_context` keyword argument.
"""
# Note: Additionally `request` and `encoding` will also be added
# to the context by the Request object.
return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {})
} # 3 获取要解析的对象
def get_parsers(self):
"""
Instantiates and returns the list of parsers that this view can use.
"""
return [parser() for parser in self.parser_classes] class BaseParser:
media_type = None
def parse(self, stream, media_type=None, parser_context=None):
raise NotImplementedError(".parse() must be overridden.")

总结:

  1. 根据流程,再次进入drf的dispatch方法,该方法对响应数据进行了二次封装同时也对数据进行了二次解析,然后,进入 request = self.initialize_request(request, *args, **kwargs)方法
  2. 在 self.initialize_request方法中通过self.get_parser_context(request)方法,获取要解析的数据,get_parser_context(self, http_request):方法返回解析的数据字典返回
  3. 在Request类中调用get_parsers(self)方法获取解析的对象,解析的随想先从创建的视图类中(BookAPIView(APIView)(局部配置))找,然后在从自己的项目文件中找(项目中 settings.py,全局配置), 最后从drf默认配置文件中(默认配置),实现数据的解析
  4. 只有在后台设置了解析的数据,才会给前台正确的响应否则报错

五、异常模块的使用

重写异常模块的目的是记录异常信息(日志记录)

5.1异常模块的使用

# 1. 配置异常模块,通过settings.py获取
REST_FRAMEWORK = {
# 异常模块配置
# Exception handling
# 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', # 默认
'EXCEPTION_HANDLER': 'api.utils.exception_handler', # 自己重写的路径
'NON_FIELD_ERRORS_KEY': 'non_field_errors', } # 2.编写异常模块,创建一个新的文件.py重写exception_handler方法
from rest_framework.response import Response
def exception_handler(exc, context):
# 在exception_handler函数完成异常信息的返回以及异常信息的logging日志
print(exc)
print(context)
print(type(exc))
# exc.detail 携带错误的信息
return Response(f'{context["view"].__class__.__name__}{exc}') # 2.2升级版
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is None: # drf没有处理的异常 response = Response({"detail": f'{context["view"].__class__.__name__}{exc}'})
# 项目阶段,将日志记录保存到文件中
return response # 2.3终极版
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is None: # drf没有处理的异常 response = Response(data={
'status': 7,
"detail": f'{context["view"].__class__.__name__}{exc}',
},
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
response = Response(status=response.status_code, data={
'status': 7,
"detail": f'{response.data.get("detail")}',
})
# 项目阶段,将日志记录保存到文件中
return response

5.2异常源码分析

 # 1. 异常出错
def dispatch(self, request, *args, **kwargs):
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
# 异常报错
response = self.handle_exception(exc)
# 二次处理响应
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response # 2 异常处理
def handle_exception(self, exc):
"""
Handle any exception that occurs, by returning an appropriate response,
or re-raising the error.
"""
if isinstance(exc, (exceptions.NotAuthenticated,
exceptions.AuthenticationFailed)):
# WWW-Authenticate header for 401 responses, else coerce to 403
auth_header = self.get_authenticate_header(self.request) if auth_header:
exc.auth_header = auth_header
else:
exc.status_code = status.HTTP_403_FORBIDDEN
# 都会走,获取异常处理函数
exception_handler = self.get_exception_handler()
# 获取请求数据内容字典
context = self.get_exception_handler_context()
# 异常函数:接收exc,context,返回response对象
response = exception_handler(exc, context) if response is None:
# 异常函数如果为空交给原生django处理
self.raise_uncaught_exception(exc)
# 异常返回
response.exception = True
return response
# 2.1获取异常处理函数具体函数,可以自己配置
def get_exception_handler(self):
"""
Returns the exception handler that this view uses.
"""
return self.settings.EXCEPTION_HANDLER

总结:

  1. 在APIView的dispatch方法中,有一个try...except...异常,将代码运行的异常都交给异常处理模块进行处理: response = self.handle_exception(exc)
  2. 在handle_exception()中从配置中映射处理异常的函数(自定义异常模块就是自定义配置函数指向自己的函数),通过self.get_exception_handler()去获取配置文件中异常函数对象,然后将数据给自己写的函数进行处理,如果没有配置则是框架中默认的
  3. 异常函数exception_handler(exe,content)处理异常,就会走自己重写的异常函数,先交给系统处理(客户端的异常),系统没处理(服务器异常),再自己处理

5.3.状态码响应模块

Response类生成对象需要的参数,以及Response类的对象可以使用的属性

  1. 参数:Response(data=响应的数据, status=响应的网络状态码, headers=想通过响应头再携带部分信息给前端)

  2. 属性:response.data response.status_code response.status_text

  3. 源码:Response类的__init__方法

总结

安装与使用django-restframework的更多相关文章

  1. django restframework 快速入门

    django restframework 快速入门 基本流程 建立 Models 依靠 Serialiers 将数据库取出的数据 Parse 为 API 的数据(可用于返回给客户端,也可用于浏览器显示 ...

  2. Django Restframework 实践(一)

    具备以下知识: django http://www.cnblogs.com/menkeyi/p/5882464.html http://www.cnblogs.com/menkeyi/p/588245 ...

  3. 安装Nginx+uWSGI+Django环境

    Ubuntu Server 12.04 安装Nginx+uWSGI+Django环境 今天要介绍的是利用APT源直接apt-get install安装配置我们所需要的环境,首先按惯例先安装MySQL和 ...

  4. django restframework serializer 增加自定义字段

    在使用django restframework serializer 序列化在django中定义的model时,有时候我们需要额外在serializer中增加一些model中没有的字段.有两种方法实现 ...

  5. django restframework

    一.django restframework 请求流程源码剖析 上面的认证一个流程是rest_framework的关于APIauth的认证流程,,这个流程试用权限.频率.版本.认证.这个四个组件都是通 ...

  6. django restframework jwt

    既然要来学习jwt(json web token),那么我们肯定是先要了解jwt的优势以及应用场景--跨域认证. $ pip install djangorestframework-jwt 传统coo ...

  7. pip 安装 和 卸载 django

    1. 在dos命令行中输入 pip 如下命令进行安装: 安装最新的版本的 Django 命令如下: pip install django 安装 指定版本的 Django 命令如下: pip insta ...

  8. win下python环境搭建以及安装pip、django

    1. 安装python并配置 下载安装python,这里我下载的是python2.7,听说2.7比较好用 地址:https://www.python.org/downloads/source/ 记住你 ...

  9. django: rest-framework的 分页和过滤

    django: rest-framework的 分页和过滤 2018年06月28日 10:09:01 weixin_42359464 阅读数:136 标签: flaskrestframeworkdja ...

  10. 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(五):测试项目

    基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...

随机推荐

  1. 吴裕雄--天生自然 PHP开发学习:Switch 语句

    <?php $favcolor="red"; switch ($favcolor) { case "red": echo "你喜欢的颜色是红色! ...

  2. ElasticSearch的9200和9300端口的区别

    9200用于外部通讯,基于http协议,程序与es的通信使用9200端口. 9300jar之间就是通过tcp协议通信,遵循tcp协议,es集群中的节点之间也通过9300端口进行通信.

  3. java将HSSFWorkbook生成的excel压缩到zip中

    思路:1.写入输入流中. 2.将输入流加到ZipOutputStream压缩流中 List<DocumentModel> list = null; try { list = documen ...

  4. 2.redis-help使用,基本命令

    redis 帮助 > help redis-cli Type: "help @<group>" to get a list of commands in < ...

  5. kafka Poll轮询机制与消费者组的重平衡分区策略剖析

    注意本文采用最新版本进行Kafka的内核原理剖析,新版本每一个Consumer通过独立的线程,来管理多个Socket连接,即同时与多个broker通信实现消息的并行读取.这就是新版的技术革新.类似于L ...

  6. 测试Java程序执行耗费的时间

    package test; public class Main { public static void main(String[] args) { long start = System.curre ...

  7. SpringBoot项目示例

    一.准备工作: 环境及工具:Eclipse+JDK8+Maven+SpringBoot 二.源码: 1.项目架构:                    2.引入pom.xml <project ...

  8. Python 学习笔记:根据输入年月区间,返回期间所有的月份

    目的: 给定一个年月区间,比如:2019.01 至 2019.05,要求返回一个包含期间所有的月份的列表,比如:['2019.01', '2019.02', '2019.03', '2019.04', ...

  9. Spring Boot原理

    Spring 钩子之BeanFactoryPostProcessor和BeanPostProcessor的源码学习 https://www.jianshu.com/p/a90a3e617ba6 spr ...

  10. NAIPC2018

    NAIPC2018 参考:http://www.cnblogs.com/LQLlulu/p/9513669.html?tdsourcetag=s_pctim_aiomsg https://www.cn ...