随笔 - 11  文章 - 0  评论 - 0  阅读 - 1637

Django Rest-Framework

Django Rest Framework

1、特点

  • 提供了定义序列化器Serializer的方法,可快速根据Django ORM或其他库自动化序列化/反序列化。
  • 提供了丰富的类视图,MiXin扩展类,简化视图的编写。
  • 丰富的定制层级:函数视图、类视图、视图集合到自动生成API,满足各种需求。
  • 多种身份认证和权限认证方式的支持。JWT
  • 内置了限流系统
  • 直观的API WEB页面
  • 可扩展性、插件丰富

2、DRF依赖

Django:1.10、1.11、2.0
Python:2.7、3.2-3.6

测试版本

drf==3.12.2
django==2.2

3、django添加drf配置

# settings.py

INSTALLED_APPS=[
  ...
  'rest_framework',
]
# 报错解决
*AttributeError: 'str' object has no attribute 'decode'*

146行新增:query = query.encode()

4、简单示例

models.py

from django.db import models

class Users(models.Model):
  """models 模型"""
    name = models.CharField(max_length=10, null=False, verbose_name='用户名', help_text='提示文本,不能为空')
    age = models.IntegerField(verbose_name='年龄')
    sex = models.BooleanField(default=1, verbose_name='性别')
    user_num = models.CharField(null=True, verbose_name='用户编号', max_length=5)
    description = models.TextField(null=True, max_length=1000, verbose_name='个性签名')

    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

serializer.py

from rest_framework.serializers import ModelSerializer
from app01 import models

class UsersSerilizer(ModelSerializer):
    """序列化器类"""

    class Meta:
        model = models.Users
        fields = '__all__'

views.py

from django.views import View
from app01 import models
from app01.serialize import UsersSerilizer
from django.http import JsonResponse

class UsersView(View):
  """视图"""
    def get(self, request):
        users = models.Users.objects.all()
        ser_obj = UsersSerilizer(instance=users, many=True)
        print(users, '--', type(ser_obj), '--', ser_obj)
        return JsonResponse(ser_obj.data, safe=False)  # JsonResponse非字典,需要加safe=False

urls.py

    url(r'users/', views.UsersView.as_view(), name='users'),

5、序列化器类

1、基础序列化器类Serializer

# 1、models.py

from django.db import models

class Users(models.Model):
    name = models.CharField(max_length=10, null=False, verbose_name='用户名', help_text='提示文本,不能为空')
    age = models.IntegerField(verbose_name='年龄')
    sex = models.BooleanField(default=1, verbose_name='性别')
    user_num = models.CharField(null=True, verbose_name='用户编号', max_length=5)
    description = models.TextField(null=True, max_length=1000, verbose_name='个性签名')

    class Meta:
        db_table = 'tb_users02'
        verbose_name = '用户02'
        verbose_name_plural = verbose_name
        

# 2、serializer.py
from rest_framework import serializers

class UsersSerializer(serializers.Serializer):  # 基础序列化器类Serializer
    # 可删减字段
    id = serializers.IntegerField()
    # name = serializers.CharField()
    sex = serializers.BooleanField()
    user_num = serializers.CharField()
    description = serializers.CharField()
    age = serializers.IntegerField()
    
# 3、urls.py
url(r'index/', views.UsersViews.as_view(), name='index'),
  
  
# 4、views.py
from django.http import JsonResponse
from django.views import View
from app02.models import *
from app02.serializer import UsersSerializer

class UsersViews(View):
    def get(self, request):
        users = Users.objects.all()
        ser_obj = UsersSerializer(many=True, instance=users)
        print(ser_obj.data, type(ser_obj))
        return JsonResponse(ser_obj.data, safe=False, json_dumps_params={'ensure_ascii': False})

2、序列化单条数据

class UsersViews(View):
    def get(self, request):
        u1 = Users.objects.get(id=1)
        ser_obj = UsersSerializer(instance=u1) # 取消 many=True
        print(u1, ser_obj.data)
        return JsonResponse(ser_obj.data, safe=False, json_dumps_params={'ensure_ascii': False})

3、ModelViewSet

可在页面查询和新增数据。但是不常用。

views.py

from rest_framework.viewsets import ModelViewSet

class UsersView(ModelViewSet): # 继承ModelViewSet  增删改查都包含进去,不需要单独写函数
    queryset = models.Users.objects.all()
    serializer_class = UsersSerilizer

urls.py

from . import views
from rest_framework.routers import DefaultRouter

urlpatterns = [
]

url_obj = DefaultRouter()
url_obj.register('users1', views.UsersView)
urlpatterns += url_obj.urls
http://127.0.0.1:8000/users1/  # 查询全部
http://127.0.0.1:8000/users1/1/  # 查询id为1

页面查询出来,下面即可修改和删除。

4、序列化器类的【反序列化】功能

进行反序列化的时候,需要对数据进行验证。

APIView 用于前端返回的是json数据,django无法解析。

# models.py

class UsersSerializer2(serializers.Serializer):  # 基础序列化器类Serializer
    # 可删减拉取的字段
    # id = serializers.IntegerField()
    name = serializers.CharField(max_length=10, min_length=3)
    sex = serializers.BooleanField()  # 1、默认约束:required=True 默认有数据 表明必须提交此字段
    user_num = serializers.CharField(allow_blank=False)  # 是否允许为空(空字符串)
    description = serializers.CharField()  # allow_null  表示是否允许传入None,默认False
    age = serializers.IntegerField(error_messages={'max-length':'太长了','required':'不能没有'})
    # 2、多传的参数,序列化器类不会校验,除非在此添加名称
    # 3、允许字段为空加上allow_null=True和allow_blank=True
    # 4、不管传不传 required=False
    

# views.py
from app02.serializer import UsersSerializer2
from rest_framework.views import APIView

class UsersViews(APIView):
    # get写法不变
    
    def post(self, request):
        ser_obj = UsersSerializer2(data=request.data)  # 由于用户提交的数据可能是json数据,django无法解析,所以使用drf来解析,需要继承APIView
        print(request.POST)
        if ser_obj.is_valid():  # 所有字段校验没问题,返回True,其中一个字段校验失败,都会返回False。
            print('校验成功之后的数据', ser_obj.validated_data)
            return JsonResponse(ser_obj.validated_data)
        else:
            print('校验失败', ser_obj.error_messages)
            return JsonResponse({'errmsg': 'check failed', 'code': '555'})

raise_exception=True

ser_obj.is_valid(raise_exception=True)

is_valid方法还可以在校验失败的时候抛出异常,通过上面的参数开启。
drf抛出异常,向前端抛出HTTP 400 Bad Request。

此报错不够,可以使用自定义校验函数、全局钩子和局部钩子。

context额外参数

在构造serializer对象时,可以通过context添加额外数据。

seri_obj = UserSerializer('users',context={'request':request})

还可通过serializer对象的context属性获取。

例如想在全局钩子函数获取请求路径,也就是request里面的属性。

# 全局钩子
    def validate(self, data):
        req_path = self.context.get('request').path

5、字段选项参数

max_length	最大长度
min_length	最小长度
-allow_blank	是否允许为空
trim_whitespace	是否截断空白字符
max_value	最大值
min_value	最小值

# 通用参数
-read_only	表示该字段仅用于序列化,默认False
	sex = serializers.BooleanField(read_only=True) # 只是序列化需要,反序列化不校验
-write_only	表示该字段仅用于反序列化,默认False
	sex = serializers.BooleanField(write_only=True) # 该字段序列化阶段不会被提取出来,反序列化必须传值过来验证
-required	表示该字段在反序列化时,必须传入
default	反序列化的默认值
-allow_null	表示该字段是否允许传入None值,默认False
validators	该字段使用的验证器
-error_messages	包含错误编号与错误信息的字典
	age = serializers.IntegerField(error_messages={'max-length':'太长了','required':'不能没有'})
label	用于html展示API页面时
help_text	用于html展示API页面时


区别:
allow_blank、allow_null、required
空字符串	 null或None	传不传参数

6、read_only和write_only

序列化和反序列化可以写在一个class里,通过上面2个参数做区分。

在之后的view里面不需要分开序列化和反序列化,只需要给参数添加上面2个区分即可。

read_only用于序列化

write_only用于反序列化

7、自定义校验函数 validators

# serializers.py

def check_name(val):
  	"""自定义校验用户名函数"""
    if not re.match('a', val):
        raise serializers.ValidationError('用户名不是a开头')
    return val


class UsersSerializer2(serializers.Serializer):
    name = serializers.CharField(validators=[check_name, ]) # 使用自定义校验函数
    sex = serializers.BooleanField()
    user_num = serializers.CharField()
    description = serializers.CharField()
    age = serializers.IntegerField()
    

# views.py
    def post(self, request):
        ser_obj = UsersSerializer2(data=request.data)
        print(request.data)
        if ser_obj.is_valid():
            return JsonResponse(ser_obj.validated_data)
        else:
            print('校验失败', ser_obj.errors) # 会打印校验失败的错误
            return JsonResponse({'errmsg': 'check failed', 'code': '555'})

8、局部钩子和全局钩子

自定义校验函数无法做到获取额外参数功能。所以引入钩子。

局部钩子

反序列化,先进行参数校验,再进行寻找局部钩子校验。自动调用执行。

字段1参数校验、字段1局部钩子、字段2参数校验、字段2局部钩子,最后执行全局钩子。

class UsersSerializer2(serializers.Serializer):
    name = serializers.CharField()
    sex = serializers.BooleanField()
    user_num = serializers.CharField()
    description = serializers.CharField()
    age = serializers.IntegerField()

    # 局部钩子
    def validate_name(self, data):  # validate_属性名
        if '666' in data:
            raise serializers.ValidationError('不能包含666')
        return data

    def validate_age(self, data):
        pass

全局钩子

对校验完成的字段所有字段进行校验。比如校验密码和再次输入密码校验等。

重写validate函数。

class UsersSerializer2(serializers.Serializer):
    name = serializers.CharField()
    sex = serializers.BooleanField()
    user_num = serializers.CharField()
    description = serializers.CharField()
    age = serializers.IntegerField()

    # 全局钩子
    def validate(self, data):
        p1 = data.pwd1
        p2 = data.pwd2
        if p1 != p2:
            raise ValidationError('两次密码不一样')
        return data

9、保存和更新数据

保存数据
# 保存方法1
	# views.py
def post(self, request):
        ser_obj = UsersSerializer2(data=request.data)
        if ser_obj.is_valid(raise_exception=True):
            print('校验成功之后的数据', ser_obj.validated_data)
            # 1、直接保存
            new_obj = Users.objects.create(**ser_obj.validated_data)
            obj = UsersSerializer2(instance=new_obj)
            return JsonResponse(obj.data)
        else:
            print('校验失败', ser_obj.errors)
            return JsonResponse({'errmsg': 'check failed', 'code': '555'})
          
          
# 保存方法2
	# views.py
    def post(self, request):
        ser_obj = UsersSerializer2(data=request.data)
        if ser_obj.is_valid(raise_exception=True):
            # 2、序列化器类对象可以触发对应的序列化器类的create方法
            new_obj = ser_obj.save()
            obj = UsersSerializer2(instance=new_obj)
            return JsonResponse(obj.data)
        else:
            print('校验失败', ser_obj.errors)
            return JsonResponse({'errmsg': 'check failed', 'code': '555'})  
          
	# serializer.py
	  class UsersSerializer2(serializers.Serializer):
  	    def create(self, validated_data):
          """自定义的create方法"""
      	  obj = Users.objects.create(**validated_data)
        	return obj
更新数据
# 更新 方式1
	# views.py
    def put(self, request):
        """更新数据"""
        se_obj = UsersSerializer2(data=request.data, partial=True)  # partial=True 部分字段校验,传递哪个字段就校验哪个字段,没传递,不校验,即便是必填的
        if se_obj.is_valid():
            id = request.data.get('id')
            objs = Users.objects.filter(id=id)
            objs.update(**se_obj.validated_data)
            obj = objs.first()
            obj = UsersSerializer2(instance=obj)
            return JsonResponse(obj.data)
        else:
            print('校验失败', se_obj.errors)
            
# 更新 方式2
	# views.py
    def put(self, request):
        """更新数据"""
        user_obj = Users.objects.filter(id=request.data.get('id'))[0]
        se_obj = UsersSerializer2(data=request.data, partial=True, instance=user_obj)
        if se_obj.is_valid():
            # save方法更新
            obj = se_obj.save()
            obj = UsersSerializer2(instance=obj)
            return JsonResponse(obj.data)
        else:
            print('校验失败', se_obj.errors)
            
	# serializer.py
  class UsersSerializer2(serializers.Serializer):
      def update(self, instance, validated_data):
        """
        :param instance: 是视图查询传递过来的原来对象
        :param validated_data: 是用户传递过来需要更新的对象
        :return: 返回修改完成的对象
        """
        instance.description = validated_data.get('description') # 根据更新的值,来进行获取、最后save
        instance.save()
        return instance

8、modelSerializer 模型类序列化器类

serializer.py

# serializer.py
from rest_framework import serializers
from app02 import models

class UsersSerializers(serializers.ModelSerializer):
    re_pwd = serializers.CharField()
    class Meta:
        model = models.Users
        # fields = ['name', 'age','re_pwd']
        fields = '__all__'
        # read_only_fields = ('id',)
        # write_only_fields = ('id',)
        # exclude = ['name', 'age']  # 排除字段
        extra_kwargs = {  # 自定义
            'id': {'read_only': True},
            'name': {'max_length': 10,
                     'error_messages': {  # 错误信息
                         'max_length': '用户名长度太长了'
                     },
                     'validators': [],  # 自定义校验函数
                     },
        }

    def validate_name(self, data):  # 局部钩子
        pass

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

views.py

from rest_framework.views import APIView
from app02 import models
from moapp import serializers
from django.http import JsonResponse

class UsersView(APIView):
    def get(self, request):
        all_user = models.Users.objects.all()
        sobj = serializers.UsersSerializers(instance=all_user, many=True)
        return JsonResponse(sobj.data, safe=False)

    def post(self, request):
        sobj = serializers.UsersSerializers(data=request.data)
        if sobj.is_valid():
            obj = sobj.save()
            obj = serializers.UsersSerializers(instance=obj)
            return JsonResponse(obj.data)
        else:
            print(sobj.errors)
            return JsonResponse({'msg': '校验失败'})

6、视图

6.1、APIView 增删改查

class UsersSerializer(serializers.ModelSerializer):

    class Meta:
        model = Users
        fields = '__all__'
        extra_kwargs = {
            'id': {
                'read_only': True
            },
        }

6.1.1、查询

6.1.1.1、查询所有
from rest_framework.views import APIView
from app02.models import Users
from vapp.serializer import UsersSerializer
from rest_framework.response import Response

class UsersView(APIView):
    # 查询所有数据
    def get(self, request):
        # 1、request.query_params
        # http://127.0.0.1:8000/vapp/users/?a=1&b=2&b=3
        print(request.query_params)  # url后面跟着?a=1&b=2 取值  ?a=1&b=2&b=3  多选传参
        print(request.query_params.get('b'))  # getlist('b') 取多值
        us = Users.objects.all()
        obj = UsersSerializer(instance=us, many=True)
        # 2、Response 当浏览器访问时,默认页面效果
        # 默认处理了obj
        return Response(obj.data)
      
      # Response解析
      # Response(data=None, status=None,template_name=None, headers=None,exception=False, content_type=None)
      	status 响应状态吗  status=status.HTTP_400_BAD_REQUEST
        template_name  响应的页面
6.1.1.2、查询单条

urls.py

url(r'users/(?P<pk>\d+)/', views.UsersView.as_view()),  # 获取单条数据

views.py

class UsersView(APIView):
    def get(self, request, pk):
        u1 = Users.objects.get(id=pk)
        obj = UsersSerializer(instance=u1)
        return Response(obj.data)

6.1.2、新增

views.py

from rest_framework.views import APIView
from app02.models import Users
from vapp.serializer import UsersSerializer
from rest_framework.response import Response

class UsersView(APIView):
      # 添加单条数据
          def post(self, request):
            ser_obj = UsersSerializer(data=request.data)
            if ser_obj.is_valid(): # 校验数据
                obj = Users.objects.create(**ser_obj.validated_data)
                new_obj = UsersSerializer(instance=obj)
                return JsonResponse(new_obj.data)
              

              

6.1.3、更新

urls.py

url(r'users/(?P<pk>\d+)/', views.UsersView.as_view()),

views.py

class UsersView(APIView):
    def put(self, request, pk):
        """更新"""
        u1 = Users.objects.get(id=pk)
        r_data = request.data
        ser_obj = UsersSerializer(instance=u1, data=r_data, partial=True)
				# partial=True 会在更新数据时,取消校验,设置其他字段可为空
        if ser_obj.is_valid():
            instance = ser_obj.save()
            obj = UsersSerializer(instance=instance)
            return Response(obj.data)
        else:
            return Response({'error': '更新失败'})

6.1.4、删除

url(r'users/(?P<pk>\d+)/', views.UsersView.as_view()),

views.py

class UsersView(APIView):
		def delete(self, request, pk):
        """删除数据"""
        Users.objects.get(id=pk).delete()
        return Response('', status=status.HTTP_200_OK)

6.2、GenericAPIView

GenericAPIView继承了APIView。实现了5个接口。

url(r'u1/$', views.UsersViewGenericApiView.as_view()),
url(r'u1/(?P<pk>\d+)/', views.UserDetailGenericAPIView.as_view()),

serializer.py

from app02.models import Users
from rest_framework import serializers

class UsersSerializer(serializers.ModelSerializer):
    class Meta:
        model = Users
        fields = '__all__'
        extra_kwargs = {
            'id': {
                'read_only': True
            },
        }

views.py

class UsersViewGenericApiView(GenericAPIView):
    # 查询全部
    queryset = Users.objects # 可根据不同的model,直接修改Users即可
    serializer_class = UsersSerializer # 同上

    def get(self, request):
        """查询全部"""
        user_list = self.get_queryset()
        user_ser = self.get_serializer(user_list, many=True)
        return Response(user_ser.data)

    def post(self, request):
      	"""新增"""
        user_ser = self.get_serializer(data=request.data)
        if user_ser.is_valid():
            user_ser.save()
            return Response(user_ser.data)
        else:
            return Response({'msg': '新增失败'})


class UserDetailGenericAPIView(GenericAPIView):
    queryset = Users.objects
    serializer_class = UsersSerializer

    def get(self, request, pk):
        """查询单条"""
        user = self.get_object()
        user_ser = self.get_serializer(user)

        return Response(user_ser.data)

    def put(self, request, pk):
        """更新单条"""
        user = self.get_object()
        ser_obj = self.get_serializer(instance=user, data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        else:
            return Response({'msg': '更新失败'})

    def delete(self, request, pk):
        """删除单条"""
        user = self.get_object().delete()

        return Response({'msg': '删除成功'})

调用多个不同的序列化器类

get_serializer_class()

views.py

class UsersViewGenericApiView(GenericAPIView):
    # 查询全部
    queryset = Users.objects

    def get_serializer_class(self): # 这里来分配不同的序列化器类
        if self.request.method == 'GET':
            return UsersSerializer
        else:
            return UsersSerializer2

    def get(self, request):
        """查询全部"""
        user_list = self.get_queryset()
        user_ser = self.get_serializer(user_list, many=True)
        return Response(user_ser.data)

    def post(self, request):
        user_ser = self.get_serializer(data=request.data)
        if user_ser.is_valid():
            user_ser.save()
            return Response(user_ser.data)
        else:
            print(user_ser.errors)
            return Response({'msg': '新增失败'})

serializer.py

class UsersSerializer(serializers.ModelSerializer):
    """校验所有字段"""

    class Meta:
        model = Users
        fields = '__all__'
        extra_kwargs = {
            'id': {
                'read_only': True
            },
        }

class UsersSerializer2(serializers.ModelSerializer):
    # 校验指定字段
    class Meta:
        model = Users
        fields = ['name', 'age']
        extra_kwargs = {
            'id': {
                'read_only': True
            },
        }

6.3、视图扩展类接口

5个视图扩展类。

  • ListModelMixin 查询全部
  • CreateModelMixin 新增数据
  • RetrieveModelMixin 查询单条
  • UpdateModelMixin 更新单条
  • DestroyModelMixin 删除单条

需要和GenericAPIView配合。

urls.py

    url(r'u1/$', views.UsersViewGenericApiView.as_view()),
    url(r'u1/(?P<pk>\d+)/', views.UserDetailGenericAPIView.as_view()),

views.py

from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
    DestroyModelMixin
  
class UsersViewGenericApiView(GenericAPIView, ListModelMixin, CreateModelMixin):
    # 查询全部
    queryset = Users.objects
    serializer_class = UsersSerializer

    def get(self, request):
        """查询全部"""
        return self.list(request)

    def post(self, request):
        """添加单条数据"""
        return self.create(request)


class UserDetailGenericAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Users.objects
    serializer_class = UsersSerializer

    def get(self, request, pk):
        """查询单条"""
        return self.retrieve(request, pk)

    def patch(self, request, pk): # 使用put更新需要把所有数据提供过来,才可以更新
        """更新单条"""
        return self.update(request, pk)

    def delete(self, request, pk):
        """删除单条"""
        return self.destroy(request, pk)

6.4、基于GenericAPIView视图子类的接口

from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView

class UsersViewGenericApiView(ListAPIView, CreateAPIView):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer

class UserDetailGenericAPIView(RetrieveAPIView, UpdateAPIView, DestroyAPIView):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer

6.5、视图基类ViewSet

使用视图基类,可讲一系列相关参数放到一个类中。

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 更新数据
  • destory 删除数据

ViewSet不再实现get、post等方法,而是实现动作action,如list()、create()等。视图只在使用as_view()方法,才将action动作与具体请求方式对应上。

好处:可以把所有方法写到一个类中,不用获取全部和获取单条都写在2个类中。

urls.py

    url(r'u2/$', views.UsersViewGenericApiView.as_view({'get': 'get_all_users'})),
    url(r'u2/(?P<pk>\d+)/', views.UsersViewGenericApiView.as_view({'get': 'get_single_user'})),

views.py

class UsersViewGenericApiView(ViewSet):

    def get_all_users(self, request):
        users = Users.objects.all()
        us_obj = UsersSerializer(instance=users, many=True)
        return Response(us_obj.data)

    def get_single_user(self, request, pk):
        u1 = Users.objects.get(id=pk)
        obj = UsersSerializer(instance=u1)
        return Response(obj.data)
      
    def post(self,request):
      	pass

6.6、视图基类和视图扩展类合并

urls.py

    url(r'u2/$', views.UsersViewGenericApiView.as_view({'get': 'list', 'post': 'create'})),
    url(r'u2/(?P<pk>\d+)/',
        views.UsersViewGenericApiView.as_view({'get': 'retrieve', 'delete': 'destory', 'patch': 'update'})),

views.py

class UsersViewGenericApiView(ViewSet, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin,
                              DestroyModelMixin):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer
    
# 进一步优化
class UsersViewGenericApiView(ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer

6.7、视图集中定义附加action动作

url(r'stu/login/',views.UserModelViewSet.as_view({'get':'login'}))

views.py

class UsersViewGenericApiView(ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer
    
    def login(self,request):
      pass

7、路由Routers

drf提供了2个router。

区别是没有APIRoot。统一路径入口。

7.1、SimpleRouter

urls.py

from rest_framework.routers import DefaultRouter, SimpleRouter
router = SimpleRouter()
router.register('users', views.UsersViewGenericApiView)
urlpatterns += router.urls

views.py

from rest_framework.viewsets import ModelViewSet

class UsersViewGenericApiView(ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer

7.2、DefaultRouter

常用。

urls.py

from rest_framework.routers import DefaultRouter, SimpleRouter
router = DefaultRouter()
router.register('users', views.UsersViewGenericApiView)
urlpatterns += router.urls

views.py

from rest_framework.viewsets import ModelViewSet

class UsersViewGenericApiView(ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer

7.2.1、defaultrouter附加action动作

需要处理业务数据,单独定义函数。

urls.py

from . import views
from rest_framework.routers import DefaultRouter, SimpleRouter

urlpatterns = []

router = DefaultRouter()
router.register('users', views.UsersViewGenericApiView)
urlpatterns += router.urls

views.py

from rest_framework.decorators import action

class UsersViewGenericApiView(ModelViewSet):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer

    @action(methods=['get'], detail=False)  # detail=True是处理单条数据 其他情况都是False
    def books(self, request):
        return Response({'msg': 'xxx'})

8、认证Authentication

和admin一样,使用的是一套session认证。

默认全局认证,每个请求都需要认证,需要添加白名单。

全局认证类

# settings.py

REST_FRAMEWORK = {
    # 认证
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'chapp.utils.my_auth.Auth',  # 自定义认证类
        'rest_framework.authentication.SessionAuthentication',  # 基于session认证
        'rest_framework.authentication.BasicAuthentication',  # 基础认证
    ],
}
# my_auth.py 自定义认证方法

from rest_framework.authentication import BasicAuthentication
from rest_framework.exceptions import AuthenticationFailed

class Auth(BasicAuthentication):
    def authenticate(self, request):
        if 1 == 1:
            return 'request.user', 'request.auth'  # 返回用户信息  认证信息
        else:
            raise AuthenticationFailed('认证失败')
# views.py

class UUU(APIView):
    def get(self, request):
        print(request.user) # 调用认证返回的用户信息 调用返回认证信息
        print(request.auth)
        return Response({'msg': 'ok'})

局部认证类

# views.py

class UUU(APIView):
    authentication_classes = [Auth,] # 指定认证类

    def get(self, request):
        print(request.user)
        print(request.auth)
        return Response({'msg': 'ok'})

9、权限 Permissions

权限控制可以限制用户对于视图的访问和对于具体的数据对象的访问。

  • 在执行视图的dispatch()方法前,对视图访问权限进行判断
  • 在通过get_object()获取具体对象时,对模型对象访问权限进行判断

提供的权限

  • AllowAny
  • IsAuthenticated 仅通过认证的用户。只能简单的判断用户是否为注册用户而无法进行更细致的判断。
# my_prom.py 自定义权限类
from rest_framework.permissions import BasePermission

class Prom(BasePermission):
    def has_permission(self, request, view):
        print('这是promission')
        return True
      
      
# settings.py
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'chapp.utils.my_promiss.Prom',  # 自定义权限配置 全局组件
        'rest_framework.permissions.AllowAny',  # 默认权限
    ],
}

# views.py
class UUU(APIView):
    permission_classes = (IsAuthenticated, Prom)  # 权限 Prom自定义用户权限 局部权限

    def get(self, request):
        print(request.user)
        print(request.auth)
        return Response({'msg': 'ok'})

10、限流 Throttling

对接口的访问频次进行限制,减轻服务器压力。

一般用于付费购买次数。

settings.py 全局配置

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        '', # 可自定义限流类
        'rest_framework.throttling.AnonRateThrottle',  # 匿名用户,未登录的
        'rest_framework.throttling.UserRateThrottle',  # 登录之后的用户
    ),
    'DEFAULT_THROTTLE_RATES': {  # 可使用second、minute、hour或者day[smhd]
        'anon': '100/day', # 或100/m
        'user': '100/day'
    }
}

views.py 局部类配置

from rest_framework.throttling import UserRateThrottle

class UUU(APIView):
    throttle_classes = (UserRateThrottle,)

    def get(self, request):
        return Response({'msg': 'ok'})

可选限流类

AnonRateThrottle

限制所有匿名未认证用户,使用IP区分。

UserRateThrottle

限制认证用户,使用user id来区分。

自定义限流类

import time
from rest_framework.throttling import BaseThrottle

visit_recode = {}
class MySelfBaseThrottling(BaseThrottle):
    """10秒之内只能访问3次"""
    # 限制访问时间
    VISIT_TIME = 10
    # 访问次数
    VISIT_COUNT = 3

    def allow_request(self, request, view):
        id = request.META.get('REMOTE_ADDR')  # 获取IP
        self.now = time.time()  # 现在时间
        if id not in visit_recode:
            visit_recode[id] = []

        self.history = visit_recode[id]  # 访问历史

        # 限制访问时间 要求上次访问时间-这次访问时间 >10s
        while self.history and self.now - self.history[-1] > self.VISIT_TIME:
            self.history.pop()  # 删除最后一条上次登录记录

        if len(self.history) >= self.VISIT_COUNT:
            return False
        else:
            self.history.insert(0, self.now)
            return True

    def wait(self):
        return self.history[-1] + self.VISIT_TIME - self.now

11、过滤 Filtering

使用django-filter增强支持。

pip install django-filter

settings.py

INSTALLED_APPS = [
  ...
  'django_filters',
]
REST_FRAMEWORK={
  ...,
  'DEFAULT_FILTER_BACKENDS':('django_filter.rest_framework.DjangoFilterBackend',)
}

views.py

class StudentListView(ListAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentSerializer()
  
  filter_fields = ('age', 'sex')

url

127.0.0.1:8000/app01/students/?sex=1

12、排序

对于排序,drf提供了OrderingFilter过滤器来帮助进行指定字段进行排序。

class StudentListView(ListAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentSerializer()
  
  filter_backends = [OrderingFilter]
  ordering_fields = ('id','age')

url

127.0.0.1:8000/app01/students/?ordering=-age

-age 降叙

age 升序

过滤之后再排序

class StudentListView(ListAPIView):
  queryset = Student.objects.all()
  serializer_class = StudentSerializer()
  
  filter_fields = ('age','sex')
  # 由于filterbackend是局部过滤,局部过滤会覆盖全局过滤,需要过滤组件核心类再次声明。
  filter_backends = (OrderingFilter,DjangoFilterBackend)
  ordering_fields= ('id','age')
  

url

127.0.0.1:8000/students/?sex=18&ordering=-age

13、分页 Pagination

settings.py

    # 全局分页 一旦设置了全局分页 drf视图扩展类里面的list方法提供的列表页都会产生分页的数量,一般不用全局
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100

自定义分页类

# 自定义分页类
class CusPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'size'  # 可控制每页获取多少条数据
    page_query_param = 'page_size'
    max_page_size = 100 # 一页最多显示多少条


# 视图
class UsersListView(RetrieveAPIView):
    queryset = Users.objects.all()
    serializer_class = UsersSerializer()
    
    pagination_class = CusPagination
#    pagination_class = None  # 关闭分页


127.0.0.1:8000/users/?page_size1=10

LimitOffsetPagination

通过偏移量获取数据

14、异常处理

统一异常处理。

settings.py

REST_FRAMEWORK={
  # 自定义配置
  'EXCEPTION_HANDLER':'chapp.utils.exceptions.create_exception_handler'
  # 默认配置 rest_framework.views.exception_handler
}

create_exception_handler.py

from rest_framework.views import exception_handler
from chapp.utils.my_excep import APIError

def create_exception_handler(exc, context):  # 自定义错误处理函数
    """
    :param exc: 错误处理对象
    :param context:  异常发生的上下文信息
    :return:
    """
    # 先调用drf默认异常处理方法,获得标准的错误响应对象
    response = exception_handler(exc, context)  # 此函数提供了一些错误,如果无法处理,他会返回None,则需要我们自己处理错误
    if response is None:
        view = context['view'] # 出错的方法或者函数名称
        if isinstance(exc, APIError):
            # 记录错误信息,一般记录到文件中,可以使用日志系统来记录
            return Response({'msg':'自定义API错误'},status=500)
				if isinstance(exc, DatabaseError):
            return Response({'msg':'服务器内部错误'},status=status.HTTP_507_INSUFFICENT_STORAGE)
        else:
          return response

    return response
class APIError(Exception):
    pass

15、自动生成接口文档

需要 coreapi 库支持。

pip install coreapi

设置接口文档访问路径

在总路由中添加接口文档路径。

文档路由对应的视图配置为 rest_framework.documentation.include_docs_urls

from rest_framework.documentation import include_docs_urls

urlpatterns = [
	url('docs/',include_docs_urls(title='站点页面标题'))
]
错误信息:AutoSchema object has no attribute get link

REST_FRAMEWORK = {
	'DEFAULT_SCHEMA_CLASS':'rest_framework.schemas.AutoSchema'
}
posted on   weikuo  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示