Django - rest - framework - 下

一、视图三部曲

https://www.cnblogs.com/wupeiqi/articles/7805382.html

使用混合(mixins)

之前得视图部分

# 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'^publishes/$', views.PublishView.as_view(),name="publish"),
    url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(),name="detail_publish"),
    url(r"^books/$", views.BookView.as_view(),name="books"),
    url(r'^books/(?P<pk>\d+)/$',views.BookDetailView.as_view(),name="detail_book")

]

------------------------------------------------------

# views.py

from rest_framework.views import APIView, Response
from app01.serializers import *


class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ret = PublishModelSerializers(publish_list, many=True)
        return Response(ret.data)

    def post(self, request):
        ps = PublishModelSerializers(data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

class PublishDetailView(APIView):
    def get(self,request,pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish)
        return Response(ps.data)

    def put(self,request,pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish,data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

    def delete(self,request,pk):
        Publish.objects.filter(pk=pk).delete()
        return Response()
    
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ret = BookModelSerializers(book_list, many=True,context={"request":request})
        return Response(ret.data)

    def post(self, request):
        bms = BookModelSerializers(data=request.data, many=False,context={"request":request})
        if bms.is_valid():
            bms.save()
            return Response(bms.data)
        else:
            return Response(bms.errors)


class BookDetailView(APIView):
    def get(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        # 序列化
        bms = BookModelSerializers(book,context={"request":request})
        return Response(bms.data)

    def put(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        bms = BookModelSerializers(book,data=request.data,context={"request":request})
        if bms.is_valid():
            bms.save()
            return Response(bms.data)
        else:
            return Response(bms.errors)

    def delete(self,reqeust,pk):
        Book.objects.filter(pk=pk).delete()
        return Response()

---------------------------------------------------
# serializers.py

# -*- coding:utf-8 -*-
from .models import *
from rest_framework import serializers


class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = "__all__"


class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
from django.db import models

# Create your models here.

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.IntegerField()
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish")
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.title

class Publish(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
models.py

 

1. mixin类编写视图

from rest_framework import mixins, generics

mixins.ListModelMixin,   mixins.CreateModelMixin,

mixins.RetrieveModelMixin,   mixins.UpdateModelMixin,   mixins.DestroyModelMixin,

generics.GenericAPIView

 

   url(r'^authors/$',views.AuthorView.as_view(),name="author"),
   url(r'^authors/(?P<pk>\d+)',views.AuthorDetailView.as_view(),name="detail_author"),

-----------------------------------------

#########################   mixin类编写视图  ##############################

from rest_framework import mixins, generics


class AuthorView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class AuthorDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
                       generics.GenericAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

------------------------------------------------

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

 

2. 使用通用的基于类的视图

from rest_framework import generics

generics.ListCreateAPIView

generics.RetrieveUpdateDestroyAPIView

 

通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。

 

#########################   使用通用得基于类得视图  ##############################

from rest_framework import generics


class AuthorView(generics.ListCreateAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers


class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

 

3. viewsets.ModelViewSet

views.AuthorModelView.as_view({"get": "list", "post": "create"})

views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})

from rest_framework  import viewsets

viewsets.ModelViewSet

 

    url(r'^authors/$', views.AuthorModelView.as_view({"get": "list", "post": "create"}), name="author"),
    url(r'^authors/(?P<pk>\d+)',
        views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detail_author"),

---------------------------------------------------

#########################   viewsets.ModelViewSet  ##############################

from rest_framework import viewsets


class AuthorModelView(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

  # 可重写,覆盖!  
  # def list(self,request,*args,**kwargs):pass

 

效果:

get  post  get  put  delete  都可访问!

 

   

 

 

http://www.cnblogs.com/yuanchenqi/articles/8719520.html
视图三部曲
5中方法: 查(全部) 查(单条) 增 删 改
逻辑封装起来了

-----------------------------------

class AuthorModelView(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers
    
(1):url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}), name='author'),
(2):url(r'^authors/$', ViewSetMixin.as_view({"get":"list","post":"create"}), name='author'),
(3):url(r'^authors/$', ViewsetMixin.View, name='author'),

一旦用户 get 方式 访问 authors:
ViewsetMixin.View():
    for method, action in actions.items(): # {"get":"list","post":"create"}
        handler = getattr(self, action)    # self.list  self.create
        setattr(self, method, handler)     # self.get = self.list  self.post = self.create
    
        # getattr(self,"get")  # self.list
        # getattr(self,"post") # self.create
    
    return self.dispatch()
    
APIView.dispatch():
    if request.method.lower() in self.http_method_names:
        handler = getattr(self,request.method.lower())
        response = handler(request,*args,**kwargs)  # self.list()
        
        return response

(ViewSetMixin)
小总结 - 笔记

 

二、认证组件

 生成随机字符串

import hashlib, time

def get_random_str(user):
    """ 生成随机 字符串 """
    ctime = str(time.time())

    md5 = hashlib.md5(bytes(user,encoding='utf-8'))
    md5.update(bytes(ctime,encoding="utf-8"))

    return md5.hexdigest()

 

update_or_create

#  update_or_create
Token.objects.update_or_create(user=user,defaults={"token":random_str})

 

返回json

# import json
# from  django.shortcuts import HttpResponse
# return HttpResponse(json.dumps(res,ensure_ascii=False))


# from django.http import JsonResponse # return JsonResponse(res) return Response(res)

 

 登录,生成随机token

url(r'^login/$', views.LoginView.as_view(), name="login")
    
---------------------------------------------

import hashlib, time

def get_random_str(user):
    """ 生成随机 字符串 """
    ctime = str(time.time())

    md5 = hashlib.md5(bytes(user,encoding='utf-8'))
    md5.update(bytes(ctime,encoding="utf-8"))

    return md5.hexdigest()


class LoginView(APIView):
    def post(self,request):
        name = request.data.get("name")
        pwd = request.data.get("pwd")

        user = User.objects.filter(name=name,pwd=pwd).first()
        res = {"state_code":1000,"msg":None}
        if user:
            random_str = get_random_str(user.name)
            #  update_or_create
            Token.objects.update_or_create(user=user,defaults={"token":random_str})
            res["token"] = random_str
        else:
            res["state_code"] = 1001 # 错误状态码
            res["msg"] = "用户名或密码错误"

        # import json
        # from  django.shortcuts import HttpResponse
        # return HttpResponse(json.dumps(res,ensure_ascii=False))

        # from django.http import JsonResponse
        # return JsonResponse(res)

        return Response(res)

--------------------------------------------------------

# models.py 

class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)


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

    def __str__(self):
        return self.token

 

效果图:

 

 

 

登录验证 - 局部

authentication_classes = [TokenAuth]

from rest_framework import exceptions

from rest_framework.authentication import BaseAuthentication

def authenticate(self,request):

  ... ... 

  if not token_obj:

     raise exceptions.AuthenticationFailed("验证失败")

  return (token_obj.user.name, token_obj)

 

from rest_framework import exceptions

# class TokenAuth(object):
#     def authenticate(self,request):
#         token = request.GET.get("token")
#         token_obj = Token.objects.filter(token=token).first()
#         if not token_obj:
#             raise exceptions.AuthenticationFailed("验证失败")
#
#         return (token_obj.user.name, token_obj)
#
#     def authenticate_header(self,request):
#         pass


from rest_framework.authentication import BaseAuthentication

class TokenAuth(BaseAuthentication):
    def authenticate(self,request):
        token = request.GET.get("token")
        token_obj = Token.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed("验证失败")

        return (token_obj.user.name, token_obj)


class BookView(APIView):
    authentication_classes = [TokenAuth]

    def get(self, request):
        book_list = Book.objects.all()
        ret = BookModelSerializers(book_list, many=True, context={"request": request})
        return Response(ret.data)

    def post(self, request):
        bms = BookModelSerializers(data=request.data, many=False, context={"request": request})
        if bms.is_valid():
            bms.save()
            return Response(bms.data)
        else:
            return Response(bms.errors)

 

登录验证 - 全局

settings 配置

  'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth']

 

# settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth']
}

-------------------------------------------
# app01.utils

from .models import *
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication

class TokenAuth(BaseAuthentication):
    def authenticate(self,request):
        token = request.GET.get("token")
        token_obj = Token.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed("验证失败")

        return (token_obj.user.name, token_obj)

--------------------------------------------
# views.py

class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ret = BookModelSerializers(book_list, many=True, context={"request": request})
        return Response(ret.data)

    def post(self, request):
        bms = BookModelSerializers(data=request.data, many=False, context={"request": request})
        if bms.is_valid():
            bms.save()
            return Response(bms.data)
        else:
            return Response(bms.errors)

-----------------------------------------
class AuthorModelView(viewsets.ModelViewSet):
authentication_classes = [] # 加上这个,前提是全局有认证;加上这个,就走自己得,不认证了,自己没有,才走全局配置得!

queryset = Author.objects.all()
serializer_class = AuthorModelSerializers

 

效果图:

     

 

                         

三、权限组件

权限 - 局部

permission_classes = [SVIPPermission]

has_permission(self,request,view):pass   # 固定得写法,根据源码来写得!

authentication_classes = []                       # 登录页面 不需要验证,在全局配置得前提下

 

class AuthorModelView(viewsets.ModelViewSet):
    authentication_classes = [TokenAuth]
    permission_classes = [SVIPPermission]

    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

----------------------------------------------
# app01.utils.SVIPPermission
class SVIPPermission(object):
    message = "只有超级用户才能访问"
    def has_permission(self,request,view):
        username = request.user
        user_type = User.objects.filter(name=username).first().user_type
        if user_type == 3:
            return True
        else:
            return False

----------------------------------------------

class LoginView(APIView):
    authentication_classes = []
    ...
    
    ...

 

权限 - 全局

settings配置:

  'DEFAULT_PERMISSION_CLASSES': ['app01.utils.SVIPPermission']

 

# settings.py

REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'], 'DEFAULT_PERMISSION_CLASSES': ['app01.utils.SVIPPermission'] }

 

效果图:

   

 

四、频率组件

 局部视图throttle

class BookView(APIView):
    # authentication_classes = [TokenAuth]
    # permission_classes = [SVIPPermission]
    throttle_classes = [VisitRateThrottle]
    
    。。。  。。。 
    
-----------------------------------------------

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)<3:
            history.insert(0,ctime)
            return True
        else:
            return False

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

 

全局视图throttle

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'],
    'DEFAULT_PERMISSION_CLASSES': ['app01.utils.SVIPPermission'],
    'DEFAULT_THROTTLE_CLASSES': ['app01.utils.VisitThrottle'],
}

 

内置throttle类

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'],
    'DEFAULT_PERMISSION_CLASSES': ['app01.utils.SVIPPermission'],
    'DEFAULT_THROTTLE_CLASSES': ['app01.utils.VisitThrottle'],
    "DEFAULT_THROTTLE_RATES": {
        "visit_rate": "1/m",
    }
}

------------------------------------

from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

http://www.cnblogs.com/yuanchenqi/articles/8719520.html

 

五、解析器

from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
"""
默认得是 JSONParser FormParser MultiPartParser 
"""

class BookView(APIView):

    parser_classes = [JSONParser,FormParser]
    
    ... 

 

request类

  django的request类和rest-framework的request类的源码解析

 

局部视图

from rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
    parser_classes = [FormParser,JSONParser]
    queryset = Publish.objects.all()
    serializer_class = PublshSerializers
    def post(self, request, *args, **kwargs):
        print("request.data",request.data)
        return self.create(request, *args, **kwargs)

 

全局视图

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    },
    "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
}

 

六、url路由控制

url(r'',include(routers.urls)),

 

from rest_framework import routers

routers = routers.DefaultRouter()

routers.register("authors",views.AuthorModelView)

 

# urls.py

from django.conf.urls import url,include
from django.contrib import admin

from app01 import views

from rest_framework import routers
routers = routers.DefaultRouter()
routers.register("authors",views.AuthorModelView)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publishes/$', views.PublishView.as_view(), name="publish"),
    url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="detail_publish"),
    url(r"^books/$", views.BookView.as_view(), name="books"),
    url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view(), name="detail_book"),

    # url(r'^authors/$',views.AuthorView.as_view(),name="author"),
    # url(r'^authors/(?P<pk>\d+)',views.AuthorDetailView.as_view(),name="detail_author"),

    # url(r'^authors/$', views.AuthorModelView.as_view({"get": "list", "post": "create"}), name="author"),
    # url(r'^authors/(?P<pk>\d+)',
    #     views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detail_author"),


    url(r'',include(routers.urls)),

    url(r'^login/$', views.LoginView.as_view(), name="login")
    
]

------------------------------------------

# views.py

from rest_framework import viewsets

class AuthorModelView(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

 

效果图

  

 

 

 

七、分页

pnp = MyPageNumberPagination()

books_page = pnp.paginate_queryset(book_list,request,self)


from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

class MyPageNumberPagination(PageNumberPagination):
    page_size = 2
    page_query_param = "page"
    page_size_query_param = "size"
    max_page_size = 2   # 限制 size 得大小 不能超过多少!!

class MyLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 1

---------------------------

class BookView(APIView):def get(self, request):

        book_list = Book.objects.all()

        pnp = MyPageNumberPagination()
        # pnp = MyLimitOffsetPagination()

        books_page = pnp.paginate_queryset(book_list,request,self)

        # ret = BookModelSerializers(book_list, many=True, context={"request": request})
        ret = BookModelSerializers(books_page, many=True)

        # return Response(ret.data)
    
     return pnp.get_paginated_response(ret.data)

 

from rest_framework import viewsets

class AuthorModelView(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

    pagination_class = MyPageNumberPagination

 

效果图

 

 

 

day99

1 CBV

2 APIView
 class BookView(APIView):pass
 url(r'^books/$', views.BookView.as_view(),name="books"),
 url(r'^books/$', View类下的view,name="books"),
 一旦访问books/:  view(request)======APIView类下的dispatch()====请求方式对应的示例方法()

3 def dispatch():
      #一 初始化操作
      # (1) 构建新的request:
      self.request=self.initial_request()
      # self.request._request
      # self.request.GET
      # self.request.data
      # (2) 执行组件
      # 认证,权限,频率
      # 认证:request.user
      self.initial(request, *args, **kwargs)
                 ====   # 认证组件
                        self.perform_authentication(request)
                           ==== request.user
                                     =====
                                          for authenticator in self.authenticators:  # [TokenAuth(),]
                                                    try:
                                                        user_auth_tuple = authenticator.authenticate(self)
                                                    except exceptions.APIException:
                                                        self._not_authenticated()
                                                        raise

                                                    if user_auth_tuple is not None:
                                                        self._authenticator = authenticator
                                                        self.user, self.auth = user_auth_tuple
                                                        return


                        # 权限组件
                        self.check_permissions(request)
                           ===========
                                 for permission in self.get_permissions():
                                        if not permission.has_permission(request, self):
                                            self.permission_denied(
                                                request, message=getattr(permission, 'message', None)
                                            )


                        # 频率组件
                        self.check_throttles(request)

                          =============
                            for throttle in self.get_throttles():  # [VisitRateThrottle(),]
                                    if not throttle.allow_request(request, self):
                                        self.throttled(request, throttle.wait()) # 受限制


       # 分发
            if request.method.lower() in self.http_method_names:
                handler = getattr(self,request.method.lower(),
                                  self.http_method_not_allowed)

            response = handler(request, *args, **kwargs)

            return response


4 序列化组件

    class PublishSerializers(serializers.Serializer):
            name = serializers.CharField()
            email = serializers.CharField()

    class PublishModelSerializers(serializers.ModelSerializer):
            class Meta:
                model=Publish
                fields="__all__"

    # queryset或者model对象-------------》json数据
    ps=PublishSerializers(queryset,many=True)
    ps.data # [{},{},{}]

    ps=PublishSerializers(model_obj,many=False)
    ps.data # {}


    # json数据-------》记录
    # 添加操作
    ps=PublishSerializers(data=request.data)
    if ps.is_valid():
       ps.save()  # create

    # 更新操作

    ps=PublishSerializers(model_obj,data=request.data)
    if ps.is_valid():
       ps.save()  # update


5 视图组件
    # 版本1:
          # Book表
            class BookView(APIView):

                def get(self,request):
                    book_list=Book.objects.all()
                    bs=BookModelSerializers(book_list,many=True,context={'request': request})
                    return Response(bs.data)
                def post(self,request):
                    # post请求的数据
                    bs=BookModelSerializers(data=request.data)
                    if bs.is_valid():
                        print(bs.validated_data)
                        bs.save()# create方法
                        return Response(bs.data)
                    else:
                        return Response(bs.errors)


            class BookDetailView(APIView):

                def get(self,request,id):

                    book=Book.objects.filter(pk=id).first()
                    bs=BookModelSerializers(book,context={'request': request})
                    return Response(bs.data)

                def put(self,request,id):
                    book=Book.objects.filter(pk=id).first()
                    bs=BookModelSerializers(book,data=request.data)
                    if bs.is_valid():
                        bs.save()
                        return Response(bs.data)
                    else:
                        return Response(bs.errors)

                def delete(self,request,id):
                    Book.objects.filter(pk=id).delete()

                    return Response()


    # 版本2:mixIn

        from rest_framework import mixins
        from rest_framework import generics

        class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
            queryset=Author.objects.all()
            serializer_class =AuthorModelSerializers

            def get(self,request, *args, **kwargs):
                return self.list(request, *args, **kwargs)
            def post(self,request, *args, **kwargs):
                return self.create(request, *args, **kwargs)


        class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
            queryset = Author.objects.all()
            serializer_class = AuthorModelSerializers

            def get(self,request,*args, **kwargs):
                return self.retrieve(request,*args, **kwargs)

            def delete(self,request,*args, **kwargs):
                return self.destroy(request,*args, **kwargs)

            def put(self,request,*args, **kwargs):
                return self.retrieve(request,*args, **kwargs)


    # 版本3:基于通用类
        from rest_framework import mixins
        from rest_framework import generics


        class AuthorView(generics.ListCreateAPIView):
            queryset=Author.objects.all()
            serializer_class =AuthorModelSerializers

        class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
            queryset = Author.objects.all()
            serializer_class = AuthorModelSerializers

    # 版本4
     class AuthorModelView(viewsets.ModelViewSet):
            queryset = Author.objects.all()
            serializer_class = AuthorModelSerializers

     url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
     url(r'^authors/(?P<pk>\d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put"

     流程:
         url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
         url(r'^authors/$', ViewSetMixin.as_view({"get":"list","post":"create"}),name="author"),
         url(r'^authors/$', ViewSetMixin类下的view),
         一旦访问 /authors/:
              ViewSetMixin
             def  view():
                for method, action in actions.items(): # {"get":"list","post":"create"}
                    handler = getattr(self, action)    # self.list  self.create
                    setattr(self, method, handler)

                self.dispatch(request, *args, **kwargs)

            APIView类下的self.dispatch
                  # 分发
                    if request.method.lower() in self.http_method_names:
                        handler = getattr(self,request.method.lower(),
                                          self.http_method_not_allowed)


                    response = handler(request, *args, **kwargs) # self.list()

                    return response


6 认证权限频率 组件

    request.META:
        {'ALLUSERSPROFILE': 'C:\\ProgramData',
        'APPDATA': 'C:\\Users\\Administrator\\AppData\\Roaming',
        'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files',
        'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files',
        'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files',
        'COMPUTERNAME': 'PC201712041709',
        'COMSPEC': 'C:\\Windows\\system32\\cmd.exe',
        'DJANGO_SETTINGS_MODULE': 'restdemo.settings',
        'FP_NO_HOST_CHECK': 'NO', 'HOMEDRIVE': 'C:',
        'HOMEPATH': '\\Users\\Administrator',
        'LOCALAPPDATA': 'C:\\Users\\Administrator\\AppData\\Local',
        'LOGONSERVER': '\\\\PC201712041709',
        'NUMBER_OF_PROCESSORS': '4', 'OS': 'Windows_NT',
        'PATH': 'C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\Scripts;C:\\Python27;E:\\MySQL Server 5.6\\bin;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\Scripts\\;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\;C:\\Users\\Administrator\\AppData\\Local\\atom\\bin',
        'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC',
        'PROCESSOR_ARCHITECTURE': 'AMD64',
        'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 60 Stepping 3, GenuineIntel',
        'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '3c03',
        'PROGRAMDATA': 'C:\\ProgramData',
        'PROGRAMFILES': 'C:\\Program Files',
        'PROGRAMFILES(X86)': 'C:\\Program Files (x86)',
        'PROGRAMW6432': 'C:\\Program Files',
        'PSMODULEPATH': 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\',
        'PUBLIC': 'C:\\Users\\Public', 'PYCHARM_HOSTED': '1', 'PYTHONIOENCODING': 'UTF-8',
        'PYTHONPATH': 'C:\\Users\\Administrator\\PycharmProjects\\s9\\restdemo', 'PYTHONUNBUFFERED': '1',
        'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SYSTEMROOT': 'C:\\Windows',
        'TEMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp', 'TMP': 'C:\\Users\\ADMINI~1\\AppData\\Local\\Temp',
        'USERDOMAIN': 'PC201712041709',
        'USERNAME': 'Administrator',
        'USERPROFILE': 'C:\\Users\\Administrator',
        'WINDIR': 'C:\\Windows', 'WINDOWS_TRACING_FLAGS': '3',
        'WINDOWS_TRACING_LOGFILE': 'C:\\BVTBin\\Tests\\installpackage\\csilogfile.log',
        'RUN_MAIN': 'true', 'SERVER_NAME': 'PC201712041709',
        'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000',
        'REMOTE_HOST': '',
        'CONTENT_LENGTH': '',
        'SCRIPT_NAME': '',
        'SERVER_PROTOCOL': 'HTTP/1.1',
        'SERVER_SOFTWARE': 'WSGIServer/0.2',
        'REQUEST_METHOD': 'GET',
        'PATH_INFO': '/authors/',
        'QUERY_STRING': 'token=8204b8e3ac40bf59ae480d17c146b51a',
        'REMOTE_ADDR': '127.0.0.1',
        'CONTENT_TYPE': 'text/plain',
        'HTTP_HOST': '127.0.0.1:8000',
        'HTTP_CONNECTION': 'keep-alive',
        'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
        'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
        'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9', 'HTTP_COOKIE': 'csrftoken=jtus3l4GJEc9TFXWYCWxkBIZprcOv7C1vFMIyOHs7Zkxt015FwVZ2KEEeDV6LOyN', 'wsgi.input': <_io.BufferedReader name=832>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}


7 解析器-----数据解析器
    from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
    parser_classes = [JSONParser,FormParser]

8 路由控制
    针对:
         url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
         url(r'^authors/(?P<pk>\d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailauthor"),


         class AuthorModelView(viewsets.ModelViewSet):

                queryset = Author.objects.all()
                serializer_class = AuthorModelSerializers



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



         class AuthorModelView(viewsets.ModelViewSet):

                queryset = Author.objects.all()
                serializer_class = AuthorModelSerializers


9 分页



10 响应器  Response
总结 - 笔记

 

REST_FRAMEWORK = {
    # 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'],
    # 'DEFAULT_PERMISSION_CLASSES': ['app01.utils.SVIPPermission'],
    # 'DEFAULT_THROTTLE_CLASSES': ['app01.utils.VisitThrottle'],
    # "DEFAULT_THROTTLE_RATES": {
    #     "visit_rate": "1/m",
    # }
    # "PAGE_SIZE":2
}
settings.py
from django.conf.urls import url,include
from django.contrib import admin

from app01 import views

from rest_framework import routers
routers = routers.DefaultRouter()
routers.register("authors",views.AuthorModelView)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publishes/$', views.PublishView.as_view(), name="publish"),
    url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(), name="detail_publish"),
    url(r"^books/$", views.BookView.as_view(), name="books"),
    url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view(), name="detail_book"),

    # url(r'^authors/$',views.AuthorView.as_view(),name="author"),
    # url(r'^authors/(?P<pk>\d+)',views.AuthorDetailView.as_view(),name="detail_author"),

    # url(r'^authors/$', views.AuthorModelView.as_view({"get": "list", "post": "create"}), name="author"),
    # url(r'^authors/(?P<pk>\d+)',
    #     views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detail_author"),


    url(r'',include(routers.urls)),

    url(r'^login/$', views.LoginView.as_view(), name="login")
    
]
urls.py
from .models import *
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication

class TokenAuth(BaseAuthentication):
    def authenticate(self,request):
        token = request.GET.get("token")
        token_obj = Token.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed("验证失败")

        return (token_obj.user.name, token_obj)

class SVIPPermission(object):
    message = "只有超级用户才能访问"
    def has_permission(self,request,view):
        username = request.user
        user_type = User.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)<3:
#             history.insert(0,ctime)
#             return True
#         else:
#             return False
#
#     def wait(self):
#         import time
#         ctime=time.time()
#         return 60-(ctime-self.history[-1])

from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)
utils.py
from django.shortcuts import render, HttpResponse


from django.views import View
from .models import *
import json
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework.response import Response


# 为queryset,model 对象 做序列化得
# class PublishSerializers(serializers.Serializer):
#     name = serializers.CharField()
#     email = serializers.CharField()


class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Publish
        fields = "__all__"


class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
    
    # 显示超链接
    publish = serializers.HyperlinkedIdentityField(
        view_name='detailpublish', # 别名 含正则表达式
        lookup_field= 'publish_id',
        lookup_url_kwarg='pk'

    )

    # publish = serializers.CharField(source="publish.pk")
    # publish = serializers.CharField()
    # authors = serializers.CharField(source="authors.all")
    # authors = serializers.SerializerMethodField()
    # def get_authors(self,obj):
    #     temp = []
    #     for obj in obj.authors.all():
    #         temp.append(obj.name)
    #     return temp

    # def create(self, validated_data):
    #     print('--->',validated_data)
    #     book = Book.objects.create(title=validated_data["title"],price=validated_data['price'],
    #                         pub_date=validated_data['pub_date'],publish_id=validated_data['publish']['pk'])
    #     book.authors.add(*validated_data['authors'])
    #
    #     return book


class AuthorModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Author
        fields = "__all__"
serializer.py
from django.db import models


# Create your models here.

class User(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("User")
    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("Publish")
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.title


class Publish(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
models.py
from django.shortcuts import render,HttpResponse

# Create your views here.

from django.views import View
from .models import *
import json
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework.response import Response

from app01.serializer import *

class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ret = PublishModelSerializers(publish_list, many=True)
        return Response(ret.data)

    def post(self, request):
        ps = PublishModelSerializers(data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)


class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish)
        return Response(ps.data)

    def put(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ps = PublishModelSerializers(publish, data=request.data)
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

    def delete(self, request, pk):
        Publish.objects.filter(pk=pk).delete()
        return Response()


from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
"""
默认得是 JSONParser FormParser  MultiPartParser
"""
# Book
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class MyPageNumberPagination(PageNumberPagination):
    page_size = 1
    page_query_param = "page"
    page_size_query_param = "size"
    max_page_size = 2  # 限制 size 得大小 不能超过多少!!
# # http://127.0.0.1:8000/books/?page=2&size=2

class MyLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 1
    # limit_query_param =
# http://127.0.0.1:8000/books/?limit=2&offset=2

# 偏移

class BookView(APIView):
    # authentication_classes = [TokenAuth]

    parser_classes = [JSONParser,FormParser]

    def get(self,request):

        print("user:--->", request.user)
        print(request.auth)

        book_list = Book.objects.all()

        # 分页 page_size 配置 setting 全局得 单独怎么设置?  写个类
        # from rest_framework.pagination import PageNumberPagination

        # pnp = PageNumberPagination()
        # pnp = MyPageNumberPagination()
        pnp = MyLimitOffsetPagination()

        books_page = pnp.paginate_queryset(book_list,request,self)

        # bs = BookModelSerializers(book_list,many=True,context={'request': request})
        bs = BookModelSerializers(books_page,many=True,context={'request': request})

        # return HttpResponse(bs.data)
        return Response(bs.data)

    def post(self,request):

        print('data:--->', request.data,type(request.data))

        # post 请求的数据
        bs = BookModelSerializers(data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()  # create 方法
            print(bs.validated_data)
            return Response(bs.data)
        else:
            return Response(bs.errors)

class BookDetailView(APIView):
    def get(self,request,id):
        book = Book.objects.filter(pk=id).first()
        # 序列化
        bs = BookModelSerializers(book)
        return Response(bs.data)

    def put(self,request,id):



        book = Book.objects.filter(pk=id).first()
        bs = BookModelSerializers(book,data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)


    def delete(self,request,id):
        Book.objects.filter(pk=id).delete()
        return Response()



# Author
# 逻辑复用
# 三种方法

#########################   mixin类编写视图  ##############################

# from rest_framework import mixins, generics
#
# class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
#     queryset = Author.objects.all()
#     serializer_class = AuthorModelSerializers
#
#     def get(self,request,*args,**kwargs):
#         return self.list(request,*args,**kwargs)
#
#     def post(self,request,*args,**kwargs):
#         return self.create(self, request, *args, **kwargs)
#
#
# class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
#     queryset = Author.objects.all()
#     serializer_class = AuthorModelSerializers
#
#     def get(self,request,pk,*args,**kwargs):
#         return self.retrieve(request,pk,*args,**kwargs)
#
#     def delete(self,request,*args,**kwargs):
#         return self.destroy(request,*args,**kwargs)
#
#     def put(self,request,*args,**kwargs):
#         return self.update(request,*args,**kwargs)


#########################   使用得通用得基于类得视图  ##############################

# from rest_framework import mixins, generics
#
# class AuthorView(generics.ListCreateAPIView):
#     queryset = Author.objects.all()
#     serializer_class = AuthorModelSerializers
#
#
# class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
#     queryset = Author.objects.all()
#     serializer_class = AuthorModelSerializers

#########################   viewsets.ModelViewSet  ##############################
# url 需要是一趟线 走一个视图类
# url 中 利用参数 来指定 什么方式 用什么方法 执行
from .utils import TokenAuth,SVIPPermission
from rest_framework import viewsets


class VisitRateThrottle(object):
    def allow_request(self,request,view):
        # 要求访问站点得频率不能超过每分钟20次
        if 1:
            # 每次来 存下来 比对一下,间隔多久 超过一分钟
            # IP, 请求首行(request.method request.path)
            #  请求头(request.meta) 请求体(request.body)
            print("meta:----->",request.META)
            print(request.META.get("REMOTE_ADDR"))  # 客户端得ip 这里面 你要保存什么  ip 时间 记录下来;
                                                      # 频率 限制 实现 功能!!!

            return True
        else:
            return False


from rest_framework.response import Response


class AuthorModelView(viewsets.ModelViewSet):

    # authentication_classes = [TokenAuth,]
    # permission_classes = [SVIPPermission,]  取配全局八
    # throttle_classes = [VisitRateThrottle]


    queryset = Author.objects.all()
    serializer_class = AuthorModelSerializers

    pagination_class = MyPageNumberPagination

# 完美!  ok

# 类得继承 , 表示形式 需求 展示 数据 ,覆盖方法 单独写 类得继承 可重写 覆盖
#
#     def list(self,request,*args,**kwargs):
#         pass


# ------------------------------------------------------

def get_random_str(user):
    import hashlib,time
    ctime=str(time.time())

    md5=hashlib.md5(bytes(user,encoding="utf8"))
    md5.update(bytes(ctime,encoding="utf8"))

    return md5.hexdigest()


class LoginView(APIView):
    authentication_classes = []
    def post(self,request):
        name = request.data.get("name")
        pwd = request.data.get("pwd")
        user = User.objects.filter(name=name,pwd=pwd).first()
        res = {"state_code":1000,"msg":None}
        if user:
            random_str = get_random_str(user.name)
            token = Token.objects.update_or_create(user=user,defaults={"token":random_str})
            res['token'] = random_str
        else:
            res["status_code"] = 1001 # 错误状态码
            res['msg'] = "用户名或密码错误"

        import json
        return Response(json.dumps(res,ensure_ascii=False))
views.py

 

八、渲染器、版本

配置:

1.添加配置

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer','rest_framework.renderers.BrowsableAPIRenderer'],
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
    'VERSION_PARAM': 'version',  # 参数
    'DEFAULT_VERSION': 'v1',  # 默认版本
}

2.设置路由:

luffycity/urls.py

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^api/(?P<version>\w+)/', include('api.urls')),
]

api/urls.py

from django.conf.urls import url
from api.views import course

urlpatterns = [
    url(r'^course/$', course.CourseView.as_view()),
]

3.获取版本

request.version 获取版本  
posted @ 2018-07-02 08:47  Alice的小屋  阅读(516)  评论(0编辑  收藏  举报