一、Django Rest Framework框架简介
该框架的核心思想就是缩短了我们编写API接口的代码量。
Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
官方文档:https://www.django-rest-framework.org/
特点:
- 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
- 提供了丰富的类视图、Mixin扩展类,简化视图的编写;
- 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
- 多种身份认证和权限认证方式的支持;
- 内置了限流系统;
- 直观的 API web 界面;
- 可扩展性,插件丰富
二、DRF的安装及配置
2.1 安装
官方文档说明
REST框架要求以下内容:
- Python(3.5、3.6、3.7、3.8、3.9)
- Django(2.2、3.0、3.1)
我们强烈建议并仅正式支持每个Python和Django系列的最新修补程序版本。
以下软件包是可选的:
- PyYAML,uritemplate(5.1+,3.0.0+)-模式生成支持。
- Markdown(3.0.0+)-对可浏览API的Markdown支持。
- Pygments(2.4.0+)-在Markdown处理中添加语法高亮显示。
- django-filter(1.0.1+)-过滤支持。
- django-guardian(1.1.1+)-对象级别权限支持。
使用pip安装:
pip install djangorestframework # DRF包
# 可选
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
或者使用Pycharm给使用的解释器安装:djangorestframework
即可
2.2 配置
安装完成DRF以后,我们需要添加rest_framework
到配置文件的INSTALLED_APPS
里面。
INSTALLED_APPS = [
...
'rest_framework',
]
接下来就可以使用DRF提供的功能进行api接口开发了。在项目中如果使用DRF框架实现API接口,主要有以下三个步骤:
- 将请求的数据(如JSON格式)转换为模型类对象
- 操作数据库
- 将模型类对象转换为响应的数据(如JSON格式)
接下来我们先简单体验一下DRF框架能够给我们带来什么优势
三、DRF框架的简单应用
我们这里先简单了解体验一番即可,后续再讲解代码的作用。
3.1 创建模型
便于我们能够更好演示出DRF的优势
class Book(models.Model):
name = models.CharField(max_length=16)
price = models.FloatField()
进行数据库迁移操作。执行以下命令:python3 manage.py makemigrations
、python3 manage.py migrate
然后我们需要在里面插入几条数据
3.2 创建序列化容器
在syudents应用目录中新建serializers.py用于保存该应用的序列化器。
创建一个BookModelSerializer用于序列化与反序列化。
from rest_framework import serializers
from app01 import models
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
model:指明该序列化器处理的数据字段来自模型类Book
fields:指明该序列化器包含模型类中的哪些字段,all
指明包含所有字段
3.3 编写视图
在app应用中的views.py文件创建视图:BookView,这里继承的方法是一个视图集;
from rest_framework.viewsets import ModelViewSet
from app01 import models
from app01 import serializer
class BookView(ModelViewSet):
serializer_class = serializer.BookModelSerializer
queryset = models.Book.objects.all()
serializer_class:指明该视图在进行序列化或反序列化时使用的序列化器
queryset:指明该视图集在查询数据时使用的查询集
3.4 定义路由
在urls.py文件内路由信息
from rest_framework.routers import SimpleRouter
from app01 import views
router = SimpleRouter() # 可以处理视图的路由器
router.register('book',views.BookView) # 向路由器中注册视图集
urlpatterns = []
urlpatterns += router.urls # 将路由器中的所以路由信息追到到django的路由列表中
3.5 运行测试
启动Django来运行我们刚才编写的项目
python3 manage.py runserver 127.0.0.1:8080
1、在浏览器中输入网址127.0.0.1:8080/book/,可以看到DRF提供的API Web浏览页面:
这种形式就等同于我们对这个Book表进行一次all查询
2、在页面底下表单部分填写书籍信息,可以访问添加新书籍的接口,保存书籍信息:
3、当我们发送POST请求新增一条数据后,展示的内容:而新增的数据也会被保存到Book表中
4、在浏览器中输入网址127.0.0.1:8080/book/2/,可以访问获取单一书籍信息的接口(id为2的书籍),呈现如下页面:
5、点击DELTE按钮,这个接口可以访问删除书籍的接口
这是我们通过浏览器访问DRF提供的API接口呈现的样子,点击旁边的JSON按钮可以将展示的内容切换成纯JSON格式的数据
综合上序提供给我们的API接口,我们通过观察URL可以发现,DRF框架非常遵守REST规范。
通过上图可以发现,当我们进行修改数据操作时,URL并没有发送变化,而是发送了一个PUT请求来更改数据的操作。
根据不同请求来达到不同的操作,上面简单的操作已经完成了5个接口:
- 查询所有数据
- 查询单条数据
- 新增数据
- 修改某条数据
- 删除某条数据
四、序列化
补充内容:我们通过POSTMAN访问DRF提供的接口得到的是JSON格式数据
api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段:
序列化: 把我们识别的数据转换成指定的格式提供给别人。
例如:我们在django中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。
反序列化:把别人提供的数据转换/还原成我们需要的格式。
例如:前端JS提供过来的json数据,对于python而言就是字符串,我们需要进行反序列化换成字典我们才能够使用。
五、DRF基本使用
5.1 APIView使用
DRF提供给了我们一种类似于VIew类的APIView类,可以让我们基于CBV模式编写视图。
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
return Response(data={
'status': 200,
'msg': 'Hello World'
})
urls.py路由
from django.urls import path
from app01 import views
urlpatterns = [
path('book/',views.BookView.as_view())
]
页面效果:使用了DRF封装的Response响应类,展示的效果是DRF框架内定义的好的web页面,将数据填充上了。
六、APIView、Request源码分析
6.1 APIView源码分析
APIView与View源码大部分都有相似之处,因为它继承自View并且在其基础上做了一些封装处理而产生的。
我们从as_view入口下手
@classmethod
def as_view(cls, **initkwargs):
# 只观察我们熟悉的代码
if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
def force_evaluation():
raise RuntimeError(
'Do not evaluate the `.queryset` attribute directly, '
'as the result will be cached and reused between requests. '
'Use `.all()` or call `.get_queryset()` instead.'
)
cls.queryset._fetch_all = force_evaluation
# 调用了父类View的as_view方法,并且传递了一些值进去(请求、有名无名分组的值)
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
# Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
return csrf_exempt(view)
调用as_view方法后,得到内部闭包函数view的内存地址,然后传递csrf_exempt函数了。
csrf_exempt会在内部调用view函数以及传递参数(请求、有名无名分组值),并且view函数将不会需要csrf_token验证。
def csrf_exempt(view_func):
def wrapped_view(*args, **kwargs):
return view_func(*args, **kwargs)
wrapped_view.csrf_exempt = True
return wraps(view_func)(wrapped_view)
调用view函数后将得到cls生成的一个对象,而这个cls则是我们在APIView里面调用父类as_view时将自己定义的类传了进去。
def view(request, *args, **kwargs):
# **initkwargs就是我们在调用as_view时传递的内容(请求、有名无名分组的值)
self = cls(**initkwargs)
self.setup(request, *args, **kwargs)
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
return self.dispatch(request, *args, **kwargs)
APIView而与View源码最大的区别就是调用的dispatch方法,实例的对象是我们自己定义的类的,然后执行对象的self.dispatch
方法(APIView类的),并且将请求与一些值传入。
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# 将原始request请求传入,进行一番封装,得到一个新的request请求
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# 判断请求是否在self.http_method_names(包含了多个HTTP请求标识)列表内
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
# 得到执行对应请求的方法内存地址并且调用了,比如方法名是get,得到其返回的内容
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
其实self.finalize_response
方法就是将我们处理请求的方法返回的值转换成JSON格式数据,将最终响应结果返回。
其中有一行就是判断我们返回的数据是否为Response类的实例:
if isinstance(response, Response):
6.2 Request对象源码分析
在上序分析APIView源码的过程中有一处提到将原生的request对象传入到了一个方法内进行了一番封装,那么再对其展开进行分析。
request = self.initialize_request(request, *args, **kwargs)
该方法执行了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
)
Request类的初始化方法(部分):
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
self._request = request # 获取原生request请求,赋值给对象的_request属性
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty
其实我们使用APIView给我们封装的request请求与原生的几乎无异:
紫色P代表伪装成对象属性的方法,每当我们通过request.属性
如果能对应上则会触发。
每当我们在继承了APIView的类里面通过request.属性
只要调用的属性不存在则触发__getattr__
这个魔法方法,然后去原生request里面查找,找到的话则返回值。
def __getattr__(self, attr):
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
如果本文对您有帮助,别忘一键3连,您的支持就是笔者最大的鼓励,感谢阅读!
技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请
点赞 收藏+关注
子夜期待您的关注,谢谢支持!
转载:https://blog.csdn.net/m0_46958731/article/details/115644033