DRF 框架总结
DRF 框架总结
安装配置
安装
pip install djangorestframework==3.12.4
版本要求:djangorestframework==3.12.4
Python (3.5, 3.6, 3.7, 3.8, 3.9)
Django (2.2, 3.0, 3.1)
版本要求:djangorestframework==3.11.2
Python (3.5, 3.6, 3.7, 3.8)
Django (1.11, 2.0, 2.1, 2.2, 3.0)
配置
在 settings.py 中配置 rest_framework
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
]
request 的变化
变化
- Django 原生的
requet是django.core.handlers.wsgi.WSGIRequest类的对象
# Django CBV
from django.views import View
class UserView(View):
def get(self,request):
request.method
request.POST
request.GET
request.body
- drf 框架,视图中的
request对象,是对django的request进行了一次封装,完善了一些功能,增加了认证、权限,解析器等功能
from rest_framework.views import APIView
from rest_framework.response import Response
class UserView(APIView):
def get(self, request, *args, **kwargs):
# request,不再是django中的request,而是又被封装了一层,
# 内部包含:django的 request、认证、解析器等。
return Response({"code": 1000, "data": "xxx"})
def post(self, request, *args, **kwargs):
return Response({"code": 1000, "data": "xxx"})
# rest_framework.request.Request 类
class Request:
def __init__(self, request, parsers=None,
authenticators=None,negotiator=None, parser_context=None):
self._request = request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
@property
def query_params(self):
return self._request.GET
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
def __getattr__(self, attr):
try:
return getattr(self._request, attr) # self._request.method
except AttributeError:
return self.__getattribute__(attr)
源码流程
举例1
# django 和 drf 的 request.POST 都能解析 url-form-encoded 类型的数据
# django一旦读取到 v1=123&v2=456&v3=999 请求头之后,
# 就会按照 {"v1":123,"v2":456,"v3":999} 解析
# postman 测试;发送 post请求;
# 查看 django的drf的request对象,获取post请求数据的区别
# 向下面两个视图发送的请求
# 举例:
url: http://127.0.0.1:8000/index/
method: POST
content-type: application/json
data: {
"data": "test"
}
# 结论:
# django request 对象无法解析 application/json 类型的数据
# django视图中的 request 对象
class IndexView(View):
def post(self, request):
# print(request.data) # django request 中不存在 request.data 属性
print(json.loads(request.body)) # 获取 post请求方法中的 json 数据
print(request.POST) # <QueryDict: {}>
response = {
'code': 1,
'msg': 'this is post method'
}
return JsonResponse(response)
# drf 中视图的 request 对象
class IndexView(APIView):
def post(self, request):
print(request.data, type(request.data)) # {"data": "test"} dict
print(request.POST) # <QueryDict: {}>
response = {
'code': 1,
'msg': 'this is post method'
}
return Response(response)
举例2
from rest_framework.views import APIView
from rest_framework.response import Response
from django.views import View
from rest_framework.request import Request
class UserView(APIView):
def get(self, request, *args, **kwargs):
# 通过对象的嵌套直接找到原 django中的 request对象,读取相关值
request._request.method
request._request.GET
request._request.POST
request._request.body
# 直接读取新request对象中的值,一般此处会对原始的数据进行一些处理,方便开发者在视图中使用。
request.query_params # 内部本质上就是 request._request.GET
# 内部读取请求体中的数据,并进行处理,
# 例如:请求者发来JSON格式,他的内部会对json字符串进行反序列化。
request.data
# 通过 __getattr__ 去访问 request._request 中的值
request.method
版本控制
URL的GET参数传递
方式
url: http://127.0.0.1:8000/index?verson=v1/
配置
# setting.py
REST_FRAMEWORK = {
"VERSION_PARAM": "version", # 版本参数 ?version=v1
# "VERSION_PARAM": "v", # 版本参数 ?v=v2
"DEFAULT_VERSION": "v1", # 默认版本号
"ALLOWED_VERSIONS": ["v1", "v2", "v3"],
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.QueryParameterVersioning"
}
获取
class VersionGet(APIView):
# 版本类 可以写在配置文件中
# versioning_class = QueryParameterVersioning
def get(request):
print(request.version) # 获取版本号
response = {
'code': 1,
'msg': 'This is get method'
}
return Response(response)
URL路径传递
方式
url: http://127.0.0.1:8000/api/v1/
配置
# setting.py
REST_FRAMEWORK = {
"DEFAULT_VERSION": "v1", # 默认版本号
"ALLOWED_VERSIONS": ["v1", "v2", "v3"],
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning"
}
获取
urlpatterns = [
path('api/<str:version>/', views.IndexView.as_view()),
]
class IndexView(APIView):
# versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
print(request.version) # v1
response = {
'code': 1,
'msg': 'this is get method'
}
return Response(response)
源码分析
认证
源码
权限
源码
序列化
drf 中为我们提供了 Serializer 主要又两大功能:
- 对请求数据的校验 进入数据库
- 对数据库查询到的对象进行序列化
数据校验
示例准备
数据表
class Role(models.Model):
""" 角色表 """
title = models.CharField(verbose_name="名称", max_length=32)
class Department(models.Model):
""" 部门表 """
title = models.CharField(verbose_name="名称", max_length=32)
class UserInfo(models.Model):
""" 用户表 """
level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
level = models.IntegerField(verbose_name="级别", choices=level_choices, default=1)
username = models.CharField(verbose_name="用户名", max_length=32)
password = models.CharField(verbose_name="密码", max_length=64)
age = models.IntegerField(verbose_name="年龄", default=0)
email = models.CharField(verbose_name="邮箱", max_length=64)
token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)
# 外键
depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
# 多对多
roles = models.ManyToManyField(verbose_name="角色", to="Role")
示例1
# post 提交数据
{
"username":"kukudehan",
"age": 18,
"level": "1",
"email":"1231@qq.com",
"email2":"12450@qq.com",
"email3":"12450@qq.com",
"roles": [1, 2]
}
# 数据校验示例一
class UserSerializer(serializers.Serializer):
username = serializers.CharField(label="姓名", min_length=6, max_length=32)
age = serializers.IntegerField(label="年龄", min_value=0, max_value=200)
# choices = level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
level = serializers.ChoiceField(label="级别", choices=models.UserInfo.level_choices)
# 第一种验证规则 用django 内置的验证
email = serializers.CharField(label="邮箱", validators=[EmailValidator, ])
# 不进行校验
email1 = serializers.CharField(label="邮箱1", )
# 第二种验证规则 自己编写验证的类
email2 = serializers.CharField(label="邮箱2", validators=[RegexValidator(r"^\w+@\w+\.\w+$")])
# 第三种验证规则 用钩子函数进行验证
email3 = serializers.CharField(label="邮箱3", )
# 局部钩子函数 只校验 email3 的数据是否符合规范
def validate_email3(self, value):
"""
钩子函数 用与验证某个字段
"""
if re.match(r"^\w+@\w+\.\w+$", value):
return value
raise exceptions.ValidationError("邮箱格式错误")
# 数据校验视图类
class UserModelView(APIView):
def post(self, request):
# request.data 既可以解析表单格式的数据 又可以解析 json 数据 很牛
data = request.data
ser = UserSerializer(data=data, )
# 校验数据是否正确
if not ser.is_valid():
# 获取错误字段信息
errors = ser.errors
return Response({'code': 1001, 'data': errors})
# 这是一个继承字典类的数据结构
data = ser.validated_data
return Response({'code': 200, 'data': data})
示例2
# post 提交数据
{
"username":"kukudehan",
"age": 18,
"email":"1231@qq.com"
}
# 数据校验示例二
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
# 想要校验的数据表
model = models.UserInfo
# 想要序列化的字段
fields = ["username", "age", "email", ]
# 部分字段的额外要求
extra_kwargs = {
'username': {"min_length": 6, "max_length": 32},
'email': {"validators": [EmailValidator, ]}
}
# 数据校验视图类
class UserModelView(APIView):
def post(self, request):
# request.data 既可以解析表单格式的数据 又可以解析 json 数据 很牛
data = request.data
ser = UserModelSerializer(data=data,)
if not ser.is_valid():
errors = ser.errors
return Response({'code': 1001, 'data': errors})
# 这是一个类似字典的数据结构
data = ser.validated_data
return Response({'code': 200, 'data': data})
示例3
# post 提交数据
{
"username":"kukudehan",
"age": 18,
"email":"1231@qq.com",
"email2":"12450@qq.com",
"email3":"12450@qq.com",
"roles": [1, 2]
}
from rest_framework import serializers
from django.core.validators import EmailValidator
# 自己编写的验证类
class RegexValidator(object):
def __init__(self, base):
self.base = str(base)
# RegexValidator(base=base)(value=value) 时执行
def __call__(self, value):
match_object = re.match(self.base, value)
if not match_object:
raise serializers.ValidationError("格式错误")
# 数据校验示例三
class UserModelSerializer(serializers.ModelSerializer):
email2 = serializers.CharField(label="邮箱2",
validators=[RegexValidator(r"^\w+@\w+\.\w+$")])
email3 = serializers.CharField(label="邮箱3")
# depart roles 这种一对多 多对多的字段 一定要用 json 发送
class Meta:
model = models.UserInfo
# 想要序列化的字段
fields = ["username", "age", "email", "email2", "email3", "depart", "roles"]
# 部分字段的额外要求
extra_kwargs = {
'username': {"min_length": 6, "max_length": 32},
'email': {"validators": [EmailValidator, ]}
}
# 局部钩子函数 只校验 email3 的数据是否符合规范
def validate_email3(self, value):
"""
钩子函数 用与验证某个字段
"""
if re.match(r"^\w+@\w+\.\w+$", value):
return value
raise exceptions.ValidationError("邮箱格式错误")
class UserModelView(APIView):
def post(self, request):
# request.data 既可以解析表单格式的数据 又可以解析 json 数据 很牛
data = request.data
ser = UserModelSerializer(data=data,)
if not ser.is_valid():
errors = ser.errors
return Response({'code': 1001, 'data': errors})
ser.validated_data.pop("email2")
ser.validated_data.pop("email3")
ser.save(level=1, password="1234")
# 这是一个类似字典的数据结构
data = ser.validated_data
return Response({'code': 200, 'data': data})
序列化
示例1 (多表序列化)
# 序列化示例一
class UserSerializers(serializers.ModelSerializer):
# 显示选择的 level
level_text = serializers.CharField(source="get_level_display")
# 显示 depart 部门一对多 内部反射机制 depart.title
# source 参数可以给字段取别名
depart = serializers.CharField(source="depart.title")
# 角色多对多字段
roles = serializers.SerializerMethodField()
# 额外的字段
extra = serializers.SerializerMethodField()
class Meta:
model = models.UserInfo
# 想要序列化的字段
fields = ["username", "age", "email",
"level_text", "depart", "roles", "extra"]
# 部分字段的额外要求
extra_kwargs = {
'username': {"min_length": 6, "max_length": 32},
'email': {"validators": [EmailValidator, ]}
}
# SerializerMethodField() 类的钩子函数 处理 roles 字段
# 注意一定要 roles = SerializerMethodField() 这个类才可以写下面的钩子函数
def get_roles(self, obj):
data_list = obj.roles.all()
return [model_to_dict(item, ["title"]) for item in data_list]
# return [model_to_dict(item, ["id", "title"]) for item in data_list]
# 钩子函数 处理自己额外添加的 extra 字段
def get_extra(self, obj):
return 666
class UserView(APIView):
""" 用户管理 """
def get(self, request):
queryset = models.UserInfo.objects.all()
ser = UserModelSerializer(instance=queryset, many=True)
return Response({'code': 0, 'data': ser.data})
- SerializerMethodField: 这是一个只读字段。它通过调用附加到的序列化程序类上的方法来获取其值。它可用于将任何类型的数据添加到对象的序列化表示中。
示例2 (多表序列化)
# 序列化示例二
class DepartModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Department
fields = "__all__"
class RoleModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = "__all__"
class UserSerializers(serializers.ModelSerializer):
# 显示选择的 level
level_text = serializers.CharField(source="get_level_display")
# 显示 depart 部门 一对多
depart = DepartModelSerializer()
# 角色多对多字段
roles = RoleModelSerializer(many=True)
class Meta:
model = models.UserInfo
# 想要序列化的字段
fields = ["username", "age", "email", "level_text", "depart", "roles"]
# 序列化视图类
class UserModelViews(APIView):
def get(self, request):
queryset = models.UserInfo.objects.all()
ser = UserSerializers(instance=queryset, many=True)
return Response({'code': 0, 'data': ser.data})
数据校验&序列化
"""
数据校验 和 序列化
注意:数据校验是将请求发送过来的数据进行校验,一般情况下校验无问题 入库
序列化是将数据库中的数据,以 json 格式进行 response
"""
from django.core.validators import EmailValidator
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from . import models
# 多表序列化
class DepartModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Department
# 要显示的字段
fields = ['id', 'title']
# 加上 extra_kwargs 字段后
extra_kwargs = {
"id": {"read_only": False},
"title": {"read_only": True}
}
class RoleModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = ["id", "title"]
extra_kwargs = {
"id": {"read_only": False},
"title": {"read_only": True}
}
class UserModelSerializer(serializers.ModelSerializer):
level_text = serializers.CharField(
source="get_level_display",
read_only=True
)
depart = DepartModelSerializer(many=False) # 如果不写 read_only = True 必须重写 create 方法
roles = RoleModelSerializer(many=True)
extra = serializers.SerializerMethodField(read_only=True)
email2 = serializers.EmailField(write_only=True)
class Meta:
model = models.UserInfo
fields = [
"username", "age", "email", "level_text",
"depart", "roles", "extra", "email2"
]
extra_kwargs = {
"age": {"read_only": True},
"email": {"validators": [EmailValidator, ]}
}
def get_extra(self, obj):
return 666
def validate_username(self, value):
return value
def create(self, validated_data):
# 由于 post 发送的是 {"depart": {"id": 1}} 所以需要将 depart 更改为 depart_id
depart_id = validated_data.pop("depart")['id']
# 由于 post 发送的是 {"roles": {"id": 1}, {"id": 2}} 所以需要将 depart 更改为 depart_id
role_id_list = [ele['id'] for ele in validated_data.pop('roles')]
# 更换
validated_data['depart_id'] = depart_id
user_object = models.UserInfo.objects.create(**validated_data)
# 多对多添加数据 类似如下:
# user_id role_id
# 1 2
# 1 3
user_object.roles.add(*role_id_list)
return user_object
# 视图类
class UserView(APIView):
def get(self, request):
queryset = models.UserInfo.objects.all()
ser = UserModelSerializer(instance=queryset, many=True)
return Response({"code": 0, "data": ser.data})
def post(self, request):
ser = UserModelSerializer(data=request.data)
if not ser.is_valid():
return Response({"code": 1001, "data": ser.errors})
ser.validated_data.pop("email2")
# save 中调用 create 方法
instance = ser.save(age=19, password="123")
return Response({'code': 0, 'data': "创建成功"})
反序列化
源码解析
视图类
-
APIView
新增了 免除csrf 请求封装、版本、认证、权限、限流的功能 最基础的 drf 视图类
-
GenericAPIView
GenericAPIView 继承 APIView,在 APIView 的基础上又增加了一些功能。
例如 get_queryset get_object等
实际在开发中一般不会直接继承它,他更多的是担任 中间人的角色,为子类提供公共功能。
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
class UserView(GenericAPIView):
queryset = models.UserInfo.objects.filter(id=1)
serializer_class = 序列化类
def get(self, request):
queryset = self.get_queryset()
ser = self.get_serializer(intance=queryset,many=True)
return Response({"code": 0, 'data': "..."})
-
ViewSetMixin
ViewSetMixin将 get/post/put/delete 等方法映射到 list、create、retrieve、update、partial_update、destroy方法中,让视图不再需要两个类。
# urls.py
from django.urls import path, re_path, include
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view({"get":"list","post":"create"})),
path('api/users/<int:pk>/', views.UserView.as_view({"get":"retrieve","put":"update","patch":"partial_update","delete":"destory"})),
]
# views.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
class UserView(GenericViewSet):
# 认证、权限、限流等
queryset = models.UserInfo.objects.filter(status=True)
serializer_class = 序列化类
def list(self, request):
# 业务逻辑:查看列表
queryset = self.get_queryset()
ser = self.get_serializer(intance=queryset, many=True)
return Response({"code": 0, 'data': "..."})
def create(self, request):
# 业务逻辑:新建
return Response({'code': 0, 'data': "..."})
def retrieve(self, request, pk):
# 业务逻辑:查看某个数据的详细
return Response({"code": 0, 'data': "..."})
def update(self, request, pk):
# 业务逻辑:全部修改
return Response({'code': 0, 'data': "..."})
def partial_update(self, request, pk):
# 业务逻辑:局部修改
return Response({'code': 0, 'data': "..."})
def destory(self, request, pk):
# 业务逻辑:删除
return Response({'code': 0, 'data': "..."})
-
GenericViewSet
GenericViewSet类中没有定义任何代码,他就是继承 ViewSetMixin 和 GenericAPIView,也就说他的功能就是将继承的两个类的功能继承到一起。
源码:
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
"""
pass
-
五大视图类
drf 中为我们提供了 5 个 用于做增、删、改(局部修改)、查列表、 查单个数据的 5 个类(需要结合GenericViewSet 使用)
ListModelMixin, CreateModelMixin,
RetrieveModelMixin`, `UpdateModelMixin`,`DestroyModelMixin
示例1
# urls.py
from django.urls import path, re_path, include
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view({"get":"list","post":"create"})),
path('api/users/<int:pk>/', views.UserView.as_view({"get":"retrieve","put":"update","patch":"partial_update","delete":"destroy"})),
]
# views.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import (
ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin,
DestroyModelMixin
)
class UserView(CreateModelMixin, ListModelMixin,
RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
queryset = models.UserInfo.objects.filter(status=True)
serializer_class = 序列化类
示例2
# urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view({"get": "list", "post": "create"})),
path('api/users/<int:pk>/', views.UserView.as_view({"get": "retrieve"})),
]
# views.py
from rest_framework import serializers
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins
from app01 import models
class UserModelSerializer(serializers.ModelSerializer):
level_text = serializers.CharField(
source="get_level_display",
read_only=True
)
extra = serializers.SerializerMethodField(read_only=True)
class Meta:
model = models.UserInfo
fields = ["username", "age", "email", "level_text", "extra"]
def get_extra(self, obj):
return 666
class UserView(mixins.ListModelMixin, mixins.RetrieveModelMixin,
mixins.CreateModelMixin, GenericViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserModelSerializer
def perform_create(self, serializer):
""" 序列化:对请求的数据校验成功后,执行保存。"""
serializer.save(depart_id=1, password="123")
示例3
# urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view(
{"get": "list", "post": "create"}
)),
path('api/users/<int:pk>/', views.UserView.as_view(
{"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}
)),
]
# views.py
from rest_framework import serializers
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins
from app01 import models
class UserModelSerializer(serializers.ModelSerializer):
level_text = serializers.CharField(
source="get_level_display",
read_only=True
)
extra = serializers.SerializerMethodField(read_only=True)
class Meta:
model = models.UserInfo
fields = ["username", "age", "email", "level_text", "extra"]
def get_extra(self, obj):
return 666
class UserView(mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserModelSerializer
def perform_create(self, serializer):
""" 序列化:对请求的数据校验成功后,执行保存。"""
serializer.save(depart_id=1, password="123")
def perform_update(self, serializer):
serializer.save()
def perform_destroy(self, instance):
instance.delete()
-
ModelViewSet
ModelViewSet 继承了 五大视图类 和 GenericViewSet类
# urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view(
{"get": "list", "post": "create"}
)),
path('api/users/<int:pk>/', views.UserView.as_view(
{"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}
)),
]
# views.py
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from app01 import models
class UserModelSerializer(serializers.ModelSerializer):
level_text = serializers.CharField(
source="get_level_display",
read_only=True
)
extra = serializers.SerializerMethodField(read_only=True)
class Meta:
model = models.UserInfo
fields = ["username", "age", "email", "level_text", "extra"]
def get_extra(self, obj):
return 666
class UserView(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserModelSerializer
# 钩子函数 可以在create前修改内容
def perform_create(self, serializer):
""" 序列化:对请求的数据校验成功后,执行保存。"""
serializer.save(depart_id=1, password="123")
-
视图类继承关系
视图类总结
- 接口与数据库操作无关, 直接继承APIView
- 接口背后需要对数据库进行操作,一般:
ModelViewSetCreateModelMixinListModelMixin
利用钩子自定义功能
重写某个方法 实现更加完善的功能

浙公网安备 33010602011771号