rest_framework自己总结的

settings.py

REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
    "DEFAULT_VERSION": "v1",
    "ALLOWED_VERSIONS": ["v1", "v2"],
    "VERSION_PARAM": "version",
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.Auth.MyAuth"],
    "DEFAULT_THROTTLE_RATES": {
        "WD": "3/m"
    }
}

urls.py

from django.conf.urls import url
from django.contrib import admin
# from serializers.views import StudentAPIView, StudentEditView, BooksAPIView
from serializers.views import StudentView, VersionView, UserView, TestAuthView,BookPageView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # url(r'^api/students', StudentAPIView.as_view()),   # get post请求
    # url(r'^api/student/(?P<id>d+)', StudentEditView.as_view()), #带有id的get patch delete请求

    # 使用我们自己写的ModelViewSet,继承ViewSetMixin进行请求的分发
    # url(r'^api/students', BooksAPIView.as_view({"get": "list", "post": "create"})),
    # url(r'^api/student/(?P<id>d+)', BooksAPIView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),

    # 使用rest_framework自带的ModelViewSet进行请求的分发,这里要注意url携带的命名参数,名字应该是pk
    # url(r'^api/students', BooksAPIView.as_view({"get": "list", "post": "create"})),
    # url(r'^api/student/(?P<pk>d+)', BooksAPIView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),

    # 自己写的测试版二,可以通用的版本
    #  url(r'^api/student$', StudentView.as_view()),
    #  url(r'^api/student/(?P<id>d+)', StudentView.as_view()),

    # 带版本控制的
    url(r'^(?P<version>[v1|v2]+)/api/student$', StudentView.as_view()),  # http://127.0.0.1:8000/v1/api/student
    url(r'^(?P<version>[v1|v2]+)/api/student/(?P<id>d+)', StudentView.as_view()),

    # 版本控制测试
    url(r'^(?P<version>[v1|v2]+)/book$', VersionView.as_view()),

    # 认证测试,权限测试,频率测试
    url(r'^user$', UserView.as_view()),
    url(r'^test', TestAuthView.as_view()),  # http://127.0.0.1:8000/test?token=20609ddd01fe4faeb0ffe7d8d8c39881

    # 分页测试
    url(r'^book_page', BookPageView.as_view()),   # http://127.0.0.1:8000/book_page?page=1&size=1
                                                  # http://127.0.0.1:8000/book_page?limit=2&offset=0
                                                  # http://127.0.0.1:8000/book_page

]

  utils文件夹下的文件  Auth.py(认证)        pagenation.py(分页)       permissions.py(权限)     throttle(频率)

# Auth.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from serializers.models import UserInfo
from rest_framework.response import Response


class MyAuth(BaseAuthentication):
    def authenticate(self, request):
        # 第一步先拿到前端传过来的token
        token = request.query_params["token"]
        # 验证token是否存在
        user_obj = UserInfo.objects.filter(token=token).first()
        if user_obj:
            return (user_obj, token)
        else:
            raise AuthenticationFailed("认证失败")
			


# pagenation.py
from rest_framework import pagination  # 分页


class MyPagenation(pagination.PageNumberPagination):
    page_size = 2
    page_query_param = 'page'
    page_size_query_param = "size"
    max_page_size = 3


class MyLimitPage(pagination.LimitOffsetPagination):
    default_limit = 1
    limit_query_param = 'limit'  # limit限制每页显示的个数
    offset_query_param = 'offset'  # 相对第一个数据的偏移量
    max_limit = 2


class MyCursorPage(pagination.CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 2
    ordering = '-id'






# permissions.py
class MyPermission(object):
    message = "您没有权限,请充值"
    def has_permission(self, request, view):
        # 权限逻辑 有权限返回True 没有返回False
        # 认证是在权限前面执行
        # request.user   user_obj
        user_obj = request.user
        if user_obj.type == 1:
            return True
        else:
            return False





# throttle.py
from rest_framework import throttling  # 频率
import time
VISIT_RECORD = {}
class MyThrottle(object):
    """
    60秒访问3次
    """
    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        """
        频率限制的逻辑
        通过返回True
        不通过返回False
        :param request:
        :param view:
        :return:
        """
        # 获取用户IP
        ip = request.META.get("REMOTE_ADDR")
        # 判断ip是否在访问记录里
        now = time.time()
        if ip not in VISIT_RECORD:
            VISIT_RECORD[ip] = [now,]
        # 如果ip在访问记录里
        history = VISIT_RECORD[ip]
        # 把当然访问时间添加到列表最前面
        history.insert(0, now)

        # 确保列表内的时间都是范围内时间
        while history and now - history[-1] > 60:
            history.pop()
        self.history = history
        # 看列表长度是否符合限制次数
        if len(history) <= 3:    # 经过这样的限制后,history列表中(60秒内)最多有三次访问记录,列表中最后的数据是据现在60秒内最早的访问记录(访问时间)
            return True
        else:
            return False

    def wait(self):
        """
        返回还剩多久可以访问
        :return:
        """
        now = time.time()
        return 60 - (now - self.history[-1])

class MyVisitThrottle(throttling.SimpleRateThrottle):
    scope = "WD"
    """
    第一  自己的类里要有scope
    第二  settings   DEFAULT_THROTTLE_RATES
    第三  DEFAULT_THROTTLE_RATES = { scope配置的变量值:xxx}
    第四 重写 get_cache_key(self, request, view)
    """
    def get_cache_key(self, request, view):
        return self.get_ident(request)			

  

views.py

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Student,UserInfo
from .serializers import StudentSerializer
from utils.Auth import MyAuth
from utils.permissions import MyPermission
from utils.throttle import MyThrottle, MyVisitThrottle
import uuid
from utils.pagenation import MyPagenation,MyLimitPage,MyCursorPage
from rest_framework.viewsets import ViewSetMixin, ModelViewSet

# Create your views here.
"""
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        return self.queryset.all()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class ListModelMixin(object):
    def list(self, request):
        queryset = self.get_queryset()
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)


class CreateModelMixin(object):
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            print(ser_obj.validated_data)
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)


class All(GenericAPIView, ListModelMixin, CreateModelMixin):
    pass


class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(student_obj)
        return Response(ser_obj.data)


class UpdateModelMixin(object):
    def update(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=student_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)


class DestroyModelMixin(object):
    def destroy(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        if student_obj:
            student_obj.delete()
            return Response("")
        else:
            return Response("删除对象不存在")


class EditAll(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass


class StudentAPIView(All):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class StudentEditView(EditAll):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    def get(self, request, id):  # 不知道为什么这里的形参id的名字必须与url(?P<id>d+)中传递参数的名字一样,可能这里传的是关键字参数吧
        return self.retrieve(request, id)

    def patch(self, request, id):
        return self.update(request, id)

    def delete(self, request, id):
        return self.destroy(request, id)


# class ModelViewSet(ViewSetMixin, All, EditAll):  # 打开注释用的是自己写的ModelViewSet,不打开用的是rest_framework封装好的ModelViewSet
#     pass


class BooksAPIView(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
"""

"""
#  自己的测试版一
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        return self.queryset.all()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        if not id:
            queryset = self.get_queryset()
            ser_obj = self.get_serializer(queryset, many=True)
        else:
            student_obj = self.get_queryset().filter(id=id).first()
            ser_obj = self.get_serializer(student_obj)

        return Response(ser_obj.data)

class CreateModelMixin(object):
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            print(ser_obj.validated_data)
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)

class UpdateModelMixin(object):
    def update(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=student_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)

class DestroyModelMixin(object):
    def destroy(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        if student_obj:
            student_obj.delete()
            return Response("")
        else:
            return Response("删除对象不存在")

class All(GenericAPIView,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin):
    pass
class StudentView(All):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    def get(self, request, id=None):
        return self.retrieve(request, id)

    def post(self, request,id=None):
        return self.create(request)

    def patch(self, request, id=None):
        return self.update(request, id)

    def delete(self, request, id=None):
        return self.destroy(request, id)
"""


"""
#  自己的测试版二,这版整理的比较好可以通用
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None
    def get_queryset(self):
        return self.queryset.all()
    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)
    def retrieve(self, request, id):
        if not id:
            queryset = self.get_queryset()
            ser_obj = self.get_serializer(queryset, many=True)
        else:
            student_obj = self.get_queryset().filter(id=id).first()
            ser_obj = self.get_serializer(student_obj)

        return Response(ser_obj.data)
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            print(ser_obj.validated_data)
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)
    def update(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=student_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)
    def destroy(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        if student_obj:
            student_obj.delete()
            return Response("")
        else:
            return Response("删除对象不存在")


class StudentView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    def get(self, request, id=None):        
        return self.retrieve(request, id)

    def post(self, request,id=None):
        return self.create(request)

    def patch(self, request, id=None):
        return self.update(request, id)

    def delete(self, request,id=None):
        return self.destroy(request, id)
"""


# url带版本验证
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None
    def get_queryset(self):
        return self.queryset.all()
    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)
    def retrieve(self, request,version, id):
        if not id:
            queryset = self.get_queryset()
            ser_obj = self.get_serializer(queryset, many=True)
        else:
            student_obj = self.get_queryset().filter(id=id).first()
            ser_obj = self.get_serializer(student_obj)
        return Response(ser_obj.data)
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            print(ser_obj.validated_data)
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)
    def update(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=student_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)
    def destroy(self, request, id):
        student_obj = self.get_queryset().filter(id=id).first()
        if student_obj:
            student_obj.delete()
            return Response("")
        else:
            return Response("删除对象不存在")

class StudentView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

    def get(self, request,version=None, id=None):
        # 这里做些版本控制的逻辑,不同版本请求做不同处理,当然这里的逻辑最好还是写到GenericAPIView类里面
        if request.version == "v1":
            return Response("v1版本的返回")
        elif request.version == "v2":
            return Response("v2版本的返回")
        return self.retrieve(request,version, id)

    def post(self, request,version=None,id=None):
        return self.create(request)

    def patch(self, request,version=None, id=None):
        return self.update(request, id)

    def delete(self, request,version=None, id=None):
        return self.destroy(request, id)

class VersionView(APIView):
    def get(self, request, version):
        print(request.version)
        print(request.versioning_scheme)
        if request.version == "v1":
            return Response("v1版本的返回")
        elif request.version == "v2":
            return Response("v2版本的返回")
        return Response("版本不存在")

class UserView(APIView):
    def post(self, request):
        # 这相当于注册
        username = request.data["username"]
        UserInfo.objects.create(username=username, token=uuid.uuid4())
        return Response("ok")

class TestAuthView(APIView):
    authentication_classes = [MyAuth,]   # 这里是局部注册认证,写在settings中是全局注册
    permission_classes = [MyPermission, ]
    throttle_classes = [MyThrottle, ]          # 使用自己写的
    # throttle_classes = [MyVisitThrottle, ]   # 使用提供的频率控制

    # 这相当于登录的认证
    def get(self, request):
        print(request.user)
        print(request.auth)
        return Response("认证测试")



from rest_framework.negotiation import DefaultContentNegotiation
class BookPageView(APIView):
    def get(self, request):
        queryset = Student.objects.all()
        my_pagenation = MyPagenation()   # page size分页方法
        # my_pagenation = MyLimitPage()        # limit offset分页方法
        # my_pagenation = MyCursorPage()      # cursor 游标分页
        page_queryset = my_pagenation.paginate_queryset(queryset, request, view=self)
        ser_obj = StudentSerializer(page_queryset, many=True)
        # return Response(ser_obj.data)
        return my_pagenation.get_paginated_response(ser_obj.data)

    def post(self, request):
        ser_obj = StudentSerializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)

  

serializers.py
from rest_framework import serializers
from .models import Student


class ClassesSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)


class CourseSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)


class StudentSerializer(serializers.ModelSerializer):
    classes_info = serializers.SerializerMethodField(read_only=True)
    course_info = serializers.SerializerMethodField(read_only=True)

    def get_classes_info(self, obj):
        ret = {
            "id": obj.classes.id,
            "name": obj.classes.name
        }
        return ret

    def get_course_info(self, obj):
        courses = obj.courses.all()
        ret = []
        for course in courses:
            ret.append({
                "id": course.id,
                'name': course.name
            })
        return ret

    class Meta:
        model = Student
        fields = "__all__"
        # fields = ["id", "name", "classes_info","course_info"]
        extra_kwargs = {
            "classes": {"write_only": True},
            "courses": {'write_only': True},
        }

  

models.py
from django.db import models

# Create your models here.
__all__ = ['Student', 'Classes', 'Course']


class Student(models.Model):
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField()
    classes = models.ForeignKey(to='Classes')
    courses = models.ManyToManyField(to='Course')
    def __str__(self):
        return self.name
    class Meta:
        db_table='01-学生表'
        verbose_name_plural=db_table
class Classes(models.Model):
    name = models.CharField(max_length=32,verbose_name='班级')
    def __str__(self):
        return self.name
    class Meta:
        db_table='02-班级表'
        verbose_name_plural=db_table
class Course(models.Model):
    name=models.CharField(max_length=32,verbose_name='课程')
    def __str__(self):
        return self.name
    class Meta:
        db_table='03-课程表'
        verbose_name_plural=db_table
class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    token = models.UUIDField()
    CHOICES = ((1, "vip"), (2, "svip"), (3, "普通用户"))
    type = models.IntegerField(choices=CHOICES, default=3)

 

app下的admin.py

from django.contrib import admin
from . import models

# Register your models here.
for table in models.__all__:
    admin.site.register(getattr(models,table))

  

原文地址:https://www.cnblogs.com/perfey/p/9959851.html