models.py
from django.db import models

class UserInfo(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    type_choices=((1,"普通用户"),(2,"VIP"),(3,"SVIP"))
    user_type=models.IntegerField(choices=type_choices,default=1)


class Token(models.Model):
    user=models.OneToOneField("UserInfo")
    token = models.CharField(max_length=128)

    def __str__(self):
        return self.token


class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publisher")
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title

class Publisher(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name

views.py

 

from django.shortcuts import render

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

class PublisherModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Publisher
        fields = "__all__"

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = "__all__"

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        fields = "__all__"

#****用户登录认证组件
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

class AuthToken(BaseAuthentication):

    def authenticate(self, request):
        token = request.query_params.get('token')   #query_params函数返回的是self._request.GET
        obj = models.Token.objects.filter(token=token).first()
        if not obj:
            raise AuthenticationFailed({'code':1001,'error':'认证失败'})
        return (obj.user.name,obj)

#*********权限组件****
from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):  #继承于BasePermission,/authous/2/才能查看每个具体的作者。否则报错
    message = "只有超级用户才能访问"
    def has_permission(self,request,view):
        username = request.user
        print(username)
        user_type = models.UserInfo.objects.filter(name=username).first().user_type
        if user_type == 3:
            return True
        else:
            return False
##*******频率组件
# from rest_framework.throttling import BaseThrottle
# VISIT_RECORD={}
# class VisitThrottle(BaseThrottle):
#
#     def __init__(self):
#         self.history=None
#
#     def allow_request(self,request,view):
#         remote_addr = request.META.get('REMOTE_ADDR')
#         print(remote_addr)
#         import time
#         ctime=time.time()
#
#         if remote_addr not in VISIT_RECORD:
#             VISIT_RECORD[remote_addr]=[ctime,]
#             return True
#
#         history=VISIT_RECORD.get(remote_addr)
#         self.history=history
#
#         while history and history[-1]<ctime-60:
#             history.pop()
#
#         if len(history)<10:
#             history.insert(0,ctime)
#             return True
#         else:
#             return False
#
#     def wait(self):
#         import time
#         ctime=time.time()
#         return 60-(ctime-self.history[-1])


class PublisherView(APIView):

    #获取所有出版社
    def get(self,request):

        pub_list = models.Publisher.objects.all()
        pub_ser = PublisherModelSerializer(pub_list,many=True)
        return Response(pub_ser.data)
    #提交出版社
    def post(self,request):

        pub_ser = PublisherModelSerializer(data=request.data)
        if pub_ser.is_valid():
            print(pub_ser.validated_data)
            pub_ser.save()
            return Response(pub_ser.data)
        else:
            return Response(pub_ser.errors)

class PublisherDetailView(APIView):
    #查看某个出版社
    def get(self,request,pk):
        pub_obj = models.Publisher.objects.filter(pk=pk).first()
        pub_ser = PublisherModelSerializer(pub_obj)
        return Response(pub_ser.data)
    #更新某个出版社
    def put(self,request,pk):
        pub_obj = models.Publisher.objects.filter(pk=pk).first()
        pub_ser = PublisherModelSerializer(pub_obj,data=request.data)
        if pub_ser.is_valid():
            pub_ser.save()
            return Response(pub_ser.data)
        else:
            return Response(pub_ser.errors)
    #删除某个出版社
    def delete(self,request,pk):
        models.Publisher.objects.filter(pk=pk).delete()
        return Response()

#****解析器
###--->根据contenttype的不同解析成不同找到不同的解析器,解析出的是字典或者QueryDict
##无论post(请求)前面传的是JSON数据还是urlencoded数据,rest framework 中的request.data都 # 帮我们解析成字典 而django中的request.POST只解析urlencode数据 from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser #默认使用前三个解析器 # 在视图类中添加 parser_classes = [JSONPaser,] #如果只写这一个,意味着只能解析JSON数据 FormParser解析urlencode数据 #*********渲染器***** from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer #在视图类中添加 renderer_classes = [JSONRenderer,] #****响应器就是Response比django原生的HttpResponse多了一些功能 #*******版本*** from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning # versioning_class = URLPathVersioning request.version,获取版本的值推荐用URLPathVersioning不用QueryParameterVersioning # # ******第二种分页 ********* from rest_framework.pagination import PageNumberPagination class MyPageNumberPagination(PageNumberPagination): page_size = 2 # 每页显示多少条数据 page_query_param = "page" # URL中输入的 page=2 page_size_query_param = "size" # 临时浏览器中使用127.0.0.1:8000/books/?page=2&size=2 第二页显示两条数据 max_page_size = 3 # 上面的size最大值,不能无限制显示10000条数据 # # ******第三种分页 ********* from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class MyLimitOffsetPagination(LimitOffsetPagination): default_limit = 1 #每页显示多少条数据 class BookView(APIView): # authentication_classes = [AuthToken,] # permission_classes = [SVIPPermission,] #依赖于上面的AuthToken # throttle_classes = [] #频率 # parser_classes = [JSONParser, FormParser] #解析器 # renderer_classes = [JSONRenderer,] #渲染器JSONRenderer只返回json数据,不带html页面 # versioning_class = QueryParameterVersioning # def get(self,request): # # book_list = models.Book.objects.all() # # from rest_framework.pagination import PageNumberPagination # # ******第一种分页 不常用********* # #在settings中配置"PAGE_SIZE"的值,定义多少条数据就显示多少 不常用 # pnp = PageNumberPagination() # book_pag = pnp.paginate_queryset(book_list,request,self) # book_ser = BookModelSerializer(book_pag,many=True) # return Response(book_ser.data) def get(self,request,*args,**kwargs): book_list = models.Book.objects.all() #**第二种分页 pnp = MyPageNumberPagination() book_pag = pnp.paginate_queryset(book_list,request,self) book_ser = BookModelSerializer(book_pag,many=True) return Response(book_ser.data) # def get(self,request): # # book_list = models.Book.objects.all() # #**第三种分页 # pnp = MyLimitOffsetPagination() # book_pag = pnp.paginate_queryset(book_list,request,self) # book_ser = BookModelSerializer(book_pag,many=True) # # return Response(book_ser.data) def post(self,request,*args,**kwargs): book_ser = BookModelSerializer(data=request.data) if book_ser.is_valid(): print(book_ser.validated_data) book_ser.save() return Response(book_ser.data) else: return Response(book_ser.errors) class BookDetailView(APIView): def get(self,request,pk,*args,**kwargs): book_obj = models.Book.objects.filter(pk=pk).first() book_ser = BookModelSerializer(book_obj) return Response(book_ser.data) def put(self,request,pk,*args,**kwargs): book_obj = models.Book.objects.filter(pk=pk).first() book_ser = BookModelSerializer(book_obj,data=request.data) if book_ser.is_valid(): book_ser.save() return Response(book_ser.data) else: return Response(book_ser.errors) def delete(self,request,pk,*args,**kwargs): models.Book.objects.filter(pk=pk).delete() return Response() ##***局部的频率组件 from app01.utils import VisitThrottle from rest_framework import viewsets class BookViewSet(viewsets.ModelViewSet): # authentication_classes = [AuthToken, ] # permission_classes=[SVIPPermission,] throttle_classes = [VisitThrottle] # 限制某个IP每分钟访问次数不能超过20次 queryset = models.Book.objects.all() serializer_class = BookModelSerializer #ModelViewSet中的分页 pagination_class = MyPageNumberPagination import uuid class AuthView(APIView): #authentication_classes = [] # 全局配置后,不让login验证,直接加空列表就不验证 def post(self,request,*args,**kwargs): ##用户登录认证 ret = {'code':1000} user = request.data.get('user') pwd = request.data.get('pwd') user = models.UserInfo.objects.filter(user=user,pwd=pwd).first() if not user: ret['code'] = 1001 ret['error'] = '用户名或密码错误' else: uid = str(uuid.uuid4()) models.Token.objects.update_or_create(user=user,defaults={'token':uid}) ret['token'] = uid return Response(ret)

 

utils.py 认证,权限,频率
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01 import models

#*********用户登录认证组件****
class AuthToken(BaseAuthentication):

    def authenticate(self, request):
        token = request.query_params.get('token')
        obj = models.Token.objects.filter(token=token).first()
        if not obj:
            raise AuthenticationFailed({'code':1001,'error':'认证失败'})
        return (obj.user.name,obj)

#*********权限组件****
from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):  #继承于BasePermission,/authous/2/才能查看每个具体的作者。否则报错
    message = "只有超级用户才能访问"
    def has_permission(self,request,view):
        username = request.user
        print(username)
        user_type = models.UserInfo.objects.filter(name=username).first().user_type
        if user_type == 3:
            return True
        else:
            return False


#*********频率组件****
from rest_framework.throttling import BaseThrottle
VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):
        remote_addr = request.META.get('REMOTE_ADDR')
        print(remote_addr)
        import time
        ctime=time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr]=[ctime,]
            return True

        history=VISIT_RECORD.get(remote_addr)
        self.history=history

        while history and history[-1]<ctime-60:
            history.pop()

        if len(history)<10:
            history.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

setting.py

REST_FRAMEWORK = {

    # "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth",],
    # "DEFAULT_PERMISSION_CLASSES": ["app01.utils.SVIPPermission",],
    # "DEFAULT_THROTTLE_CLASSES":["app01.utils.VisitThrottle",],
    #'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer','rest_framework.renderers.BrowsableAPIRenderer',],
    # "PAGE_SIZE":2,
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
    'ALLOWED_VERSIONS':['v1','v2'], # 允许的版本
    'VERSION_PARAM':'version', # 参数
    'DEFAULT_VERSION':'v1', # 默认版本
}
#如果加版本url要如下配置(?P<version>\w+),如果继承的是APIview,方法中要加*args,**kwargs,
# 如果不加版本就不用加*args,**kwargs,获取版本用request.version,
#url(r'^(?P<version>\w+)/book/$', views.BookView.as_view()),request.version,获取版本

#url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),这种只能写v1/v2,所以用w+

urls.py

 

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publisher/$', views.PublisherView.as_view()),
    url(r'^publisher/(\d+)/$', views.PublisherDetailView.as_view()),

    # url(r'^book/$', views.BookView.as_view()),
    # url(r'^book/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
    #加版本
    url(r'^(?P<version>\w+)/book/$', views.BookView.as_view()),
    url(r'^(?P<version>\w+)/book/(?P<pk>\d+)/$', views.BookDetailView.as_view()),


    url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"),
    url(r'^books/(?P<pk>\d+)/$', views.BookViewSet.as_view({
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            }),name="book_detail"),

    url(r'^auth/$', views.AuthView.as_view()),
]