rest_framwork组件

rest framework介绍 (CBV(class base views))

在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

增:校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
删:判断要删除的数据是否存在 -> 执行数据库删除
改:判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
查:查询数据库 -> 将数据序列化并返回

解析url中的 as_view()

url(r'^publishers/$', views.PublishViewSet.as_view(),name="publish_list"),  

继承

APIView继承自View,APIView中有as_view方法,方法中会执行下面这段代码

执行了父类的as_view方法,得到view函数,执行dispatch方法(一切的开始)

 

序列化

序列化用于对用户请求数据进行验证和数据进行序列化

第一种表示方法——Serializers

from rest_framework import serializers
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response


class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    price = serializers.IntegerField()
    pub_date = serializers.DateField()


class TestView(APIView):
    def get(self, request, *args, **kwargs):
        # 序列化,将数据库查询字段序列化为字典
        obj = models.Book.objects.all()
        ser = BookSerializer(obj, many=True)
        # 如果不是queryset,就不用加many=True
        # obj = models.Book.objects.all().first()
        # ser = BookSerializer(obj, many=False)
        return Response(ser.data)

    def post(self, request, *args, **kwargs):
        # 验证,对请求发来的数据进行验证
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
        else:
            print(ser.errors)
        return Response('Post请求')
View Code

第二种表示方法——ModelSerializers:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from app01 import models


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = "__all__"      # 全部
        # fields = ['title', 'price']    只查两项
        # depth = 2       # 查询深度
        # exclude = ('price',)  除了price不查询


class TestView(APIView):
    def get(self, request, *args, **kwargs):
        # 序列化,将数据库查询字段序列化为字典
        obj = models.Book.objects.all()
        ser = BookSerializer(obj, many=True)
        # 如果不是queryset,就不用加many=True
        # obj = models.Book.objects.all().first()
        # ser = BookSerializer(obj, many=False)
        return Response(ser.data)

    def post(self, request, *args, **kwargs):
        # 验证,对请求发来的数据进行验证
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()      # create 方法
            return Response(ser.data)
        else:
            print(ser.errors)
        return Response('Post请求')
View Code

 特殊取值(取user_type对应的中文)

class UserInfo(models.Model):
    user_type_choices = (
        (1,'普通用户'),
        (2,'VIP'),
        (3,'SVIP'),
    )
    user_type = models.IntegerField(choices=user_type_choices)
class UserInfoSerializer(serializers.Serializer):
    xxxxx = serializers.CharField(source="user_type")   # row.user_type  source将xxxx对应为user_type
    oooo = serializers.CharField(source="get_user_type_display")    # row.get_user_type_display()
    
数据:[{"xxxx":1,"oooo":"普通用户"}]

多表查询

一对多查询通过source实现

from django.db import models


class UserGroup(models.Model):
    title = models.CharField(max_length=32)


class UserInfo(models.Model):
    user_type_choices = (
        (1,'普通用户'),
        (2,'VIP'),
        (3,'SVIP'),
    )
    user_type = models.IntegerField(choices=user_type_choices)

    username = models.CharField(max_length=32,unique=True)
    password = models.CharField(max_length=64)

    group = models.ForeignKey("UserGroup")
    roles = models.ManyToManyField("Role")


class UserToken(models.Model):
    user = models.OneToOneField(to='UserInfo')
    token = models.CharField(max_length=64)


class Role(models.Model):
    title = models.CharField(max_length=32)
models
from rest_framework.views import APIView
from rest_framework import serializers
from . import models
from rest_framework.response import Response


class UserInfoSerializers(serializers.Serializer):
    user_type = serializers.IntegerField()
    user_type_choices = serializers.CharField(source="get_user_type_display")
    group = serializers.CharField(source="group.title")      

 多对多通过自定义实现

class UserInfoSerializers(serializers.Serializer):
    user_type = serializers.IntegerField()
    user_type_choices = serializers.CharField(source="get_user_type_display")
    group = serializers.CharField(source="group.title")
    rls = serializers.SerializerMethodField()

    def get_rls(self, obj):       # get_rls和上边rls要对应 
        ret = []
        for item in obj.roles.all():
            print(item)
            ret.append({"id": item.id, "title": item.title})
        return ret
View

 在视图中生成url

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^userinfo/$', views.UserInfoView.as_view(), ),
    url(r'^group/(?P<pk>\d+)$', views.GroupView.as_view(), name='gp'),
urls
from rest_framework.views import APIView
from rest_framework import serializers
from . import models
from rest_framework.response import Response
from django.http import HttpResponse
import json


class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class UserInfoSerializers(serializers.Serializer):
    group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
    user_type = serializers.IntegerField()
    user_type_choices = serializers.CharField(source="get_user_type_display")
    # group = serializers.CharField(source="group.id")
    rls = serializers.SerializerMethodField()

    def get_rls(self, obj):
        ret = []
        for item in obj.roles.all():
            print(item)
            ret.append({"id": item.id, "title": item.title})
        return ret


class UserInfoView(APIView):
    def get(self, request):
        obj = models.UserInfo.objects.all()
        ser = UserInfoSerializers(obj, many=True, context={'request': request})
        return Response(ser.data)


class GroupSerializers(serializers.Serializer):
    class Meta:
        model = models.UserGroup
        fields = '__all__'


class GroupView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        obj = models.UserGroup.objects.filter(pk=pk).first()
        ser = GroupSerializers(obj, many=False)
        ret = json.dumps(ser.data, ensure_ascii=False)
        return HttpResponse(ret)
View

group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_field='group_id', lookup_url_kwarg='pk')
lookup_url_kwarg='pk'是和url中的(?P<pk>\d+)$'的pk对应,lookup_field='group_id'是取group的id值
ser = UserInfoSerializers(obj, many=True, context={'request': request}) context是必须添加的

序列化验证钩子(validate+校验字段名)

class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"

    # 局部钩子
    def validate_title(self, attrs):
        if attrs.startswith("666"):
            raise ValidationError("不能以666开头")
        return attrs

    # 全局钩子
    def validate(self, attrs):

        return attrs
View

 

 视图

a. GenericAPIView(没什么用)

from rest_framework import serializers
from . import models
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response


class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = '__all__'


class RoleView(GenericAPIView):
    queryset = models.Role.objects.all()
    serializer_class = RoleSerializers

    def get(self, request, *args, **kwargs):
         # 获取数据
        obj = self.get_queryset()
        # 序列化
        ser = self.get_serializer(obj, many=True)
        return Response(ser.data)
View

b. GenericViewSet

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^role/$', views.RoleView.as_view({'get': 'list'}), ),


# 和view里边的list方法做对应关系
urls
class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = '__all__'


class RoleView(GenericViewSet):
    queryset = models.Role.objects.all()
    serializer_class = RoleSerializers

    def list(self, request, *args, **kwargs):
         # 获取数据
        obj = self.get_queryset()
        # 序列化
        ser = self.get_serializer(obj, many=True)
        return Response(ser.data)
View

c. ModelViewSet

class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^role/$', views.RoleView.as_view({'get': 'list', 'post': 'create'}), ),
    url(r'^role/(?P<pk>)\d+/$', views.RoleView.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update', 'patch': 'partial_update'}), ),
   
]
urls
class RoleView(ModelViewSet):
    queryset = models.Role.objects.all()
    serializer_class = RoleSerializers
View

a. 增删改查 ModelViewSet

b. 增删 CreateModelMixin,DestroyModelMixin GenericViewSet

c. 复杂逻辑 GenericViewSet 或 APIView

 

路由

会自动生成增删改查等url

from django.conf.urls import url, include
from django.contrib import admin
from app01 import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register(r'role', views.RoleView)


urlpatterns = [
    url(r'^', include(router.urls)),
]
urls

 

 认证

a.用户url传入的token认证

from rest_framework.authentication import BasicAuthentication
from rest_framework import exceptions


class MyAuthentication(BasicAuthentication):
    def authenticate(self, request):
        token = request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('Token认证失败')
        else:
            return token_obj.username, token_obj.token


# 验证通过返回元祖,第一个参数和request.user是对应的,所以最好是用户名

class RoleView(ModelViewSet):
    authentication_classes = [MyAuthentication, ]
    queryset = models.Role.objects.all()
    serializer_class = RoleSerializers
View

 b.用户登录添加token

class RoleView(ModelViewSet):
    authentication_classes = []
    queryset = models.Role.objects.all()
    serializer_class = RoleSerializers

    def post(self, request, *args, **kwargs):
        res = {'state_code': 1000, 'msg': None}
        try:
            name = request._request.POST.get('username')
            pwd = request._request.POST.get('password')
            user = models.UserInfo.objects.filter(username=name, password=pwd).first()
            if not user:
                res["state_code"] = 1001  # 错误状态码
                res["msg"] = "用户名或者密码错误"
            else:
                # 为用户创建token
                token = md5(name)
                # 存在就更新,否则就创建
                models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
                res['token'] = token
        except Exception as e:
            res['state_code'] = 1002
            res['msg'] = '请求异常'
        return Response(res)
View

BasicAuthentication、SessionAuthentication、TokenAuthentication、JSONWebTokenAuthentication 都属于认证都继承BaseAuthentication,方法类似

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',   # 基本认证
        'rest_framework.authentication.SessionAuthentication',  # session认证
    )
}
Setting

 

权限

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        message = '只有SVIP可以访问'
        if request.user != 3:
            return False
        return True


# 局部
permission_classes = [MyPermission, ]
View

 

频率

from rest_framework.throttling import SimpleRateThrottle


class VisitThrottle(SimpleRateThrottle):
    # 配置文件中进行配置
    scope = 'Luffy'

    def get_cache_key(self, request, view):
        return self.get_ident(request)


class UserThrottle(SimpleRateThrottle):
    scope = 'LuffyUser'


局部
throttle_classes = [VisitThrottle, ]
View
REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_RATES": {
        "Luffy": '3/m',
        "LuffyUser": '10/m',
    }
}
Setting

 

 版本

a.url的get传参方式

/user?version=v1

REST_FRAMEWORK = {
    'DEFAULT_VERSION': 'v1',            # 默认版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
    'VERSION_PARAM': 'version'          # URL中获取值的key
}
setting
from rest_framework.versioning import QueryParameterVersioning

class TestView(APIView):
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):

        # 获取版本
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)

        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)

        return Response('GET请求,响应内容')
View Code

b.基于url正则表达式

/v1/user/

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning'
    'DEFAULT_VERSION': 'v1',            # 默认版本
    'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
    'VERSION_PARAM': 'version'          # URL中获取值的key
}
setting
class TestView(APIView):
    # 局部
    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):
        # 获取版本
        print(request.version)
        # 获取版本管理的类
        print(request.versioning_scheme)

        # 反向生成URL
        reverse_url = request.versioning_scheme.reverse('test', request=request)
        print(reverse_url)
View
urlpatterns = [
    url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
]
urls

 

 解析器

用于处理不同请求头数据

REST_FRAMEWORK = {
    "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser']
                }
setting
class ParserView(APIView):
    # parser_classes = [JSONParser,FormParser,]
        """
        JSONParser:表示只能解析content-type:application/json头
        FormParser:表示只能解析content-type:application/x-www-form-urlencoded头
        """

    def post(self,request,*args,**kwargs):
        """
        允许用户发送JSON格式数据
        a. content-type: application/json
        b. {'name':'alex',age:18}
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        """
        1. 获取用户请求
        2. 获取用户请求体
        3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较
        4. JSONParser对象去请求体
        5. request.data
        """
        print(request.data)

        return HttpResponse('ParserView')
View

 

 dispatch

 

 

 

 

  

posted @ 2019-04-19 17:13  CrazyDemo  阅读(211)  评论(0编辑  收藏  举报