GVKun编程网logo

从Django Rest Framework响应中删除空字段(django删除项目)

34

在这篇文章中,我们将带领您了解从DjangoRestFramework响应中删除空字段的全貌,包括django删除项目的相关情况。同时,我们还将为您介绍有关Django-rest-framework-

在这篇文章中,我们将带领您了解从Django Rest Framework响应中删除空字段的全貌,包括django删除项目的相关情况。同时,我们还将为您介绍有关Django - rest - framework - 下、django rest framework、Django REST framework 1、Django REST framework 中依赖于格式的字段表示的知识,以帮助您更好地理解这个主题。

本文目录一览:

从Django Rest Framework响应中删除空字段(django删除项目)

从Django Rest Framework响应中删除空字段(django删除项目)

我已经使用django-rest-framework开发了一个API。我正在使用ModelSerializer返回模型的数据。

models.py

class MetaTags(models.Model):    title = models.CharField(_(''Title''), max_length=255, blank=True, null=True)    name = models.CharField(_(''Name''), max_length=255, blank=True, null=True)

序列化器

class MetaTagsSerializer(serializers.ModelSerializer):    class Meta:        model = MetaTags

响应

{    "meta": {        "title": null,        "name": "XYZ"    }}

理想情况下,API响应中不存在的任何值都不应在响应中发送。当title是时,null我希望响应为:

{    "meta": {        "name": "XYZ"    }}

答案1

小编典典

我发现此解决方案是最简单的。

from collections import OrderedDictfrom rest_framework import serializersclass NonNullModelSerializer(serializers.ModelSerializer):    def to_representation(self, instance):        result = super(NonNullModelSerializer, self).to_representation(instance)        return OrderedDict([(key, result[key]) for key in result if result[key] is not None])

Django - rest - framework - 下

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 获取版本

django rest framework

django rest framework

1 设置版本信息

from rest_framework.versioning import URLPathVersioning

1.1 settings.py 

全局设置版本信息

#全局设置版本信息
REST_FRAMEWORK={
    ''DEFAULT_VERSIONING_CLASS'':''rest_framework.versioning.URLPathVersioning'',
    ''VERSION_PARAM'':''version'',
    ''DEFAULT_VERSION'':''v1'',
    ''ALLOWED_VERSIONS'':[''v1'',''v2''],
    ''PAGE_SIZE'':1,
}

1.2 day97luffcity/urls.py

在url中体现版本信息

from django.contrib import admin
from django.urls import path,include,re_path
from api import urls

urlpatterns = [
    path(''admin/'', admin.site.urls),
    path(''api/<str:version>/'',include(''api.urls'')),
]

 

1.3 views/course.py 

在视图中查看版本信息

from rest_framework.views import APIView
from rest_framework.versioning import URLPathVersioning
class CoursesView(APIView):

    #设置版本信息
    #versioning_class = URLPathVersioning

    def get(self,request,*args,**kwargs):
        res=BaseResponse()
        #查看版本信息
        #print(request.version)

 2 分页处理

from rest_framework.pagination import PageNumberPagination

2.1 settings.py

在全局设置中设置分页的信息

#全局设置版本信息
REST_FRAMEWORK={
    ''DEFAULT_VERSIONING_CLASS'':''rest_framework.versioning.URLPathVersioning'',
    ''VERSION_PARAM'':''version'',
    ''DEFAULT_VERSION'':''v1'',
    ''ALLOWED_VERSIONS'':[''v1'',''v2''],
    ''PAGE_SIZE'':1,
}

 

 

2.2 view/course.py 

在视图中查看版本信息

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import URLPathVersioning
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from api.serializers.course import CourseSerializer
from api.serializers.course import CourseModelSerializer
from api import models
from api.utils.response import BaseResponse


class CoursesView(APIView):

    #设置版本信息
    #versioning_class = URLPathVersioning

    def get(self,request,*args,**kwargs):
        res=BaseResponse()
        #查看版本信息
        #print(request.version)
        try:
            #方式一
            course_set=models.Course.objects.all()
            # 分页的处理
            page = PageNumberPagination()
            ser_page = page.paginate_queryset(course_set, request, self)
            #ser=CourseSerializer(instance=ser_page,many=True)
            ser = CourseModelSerializer(instance=ser_page,many=True)
            res.code=1000
            res.data=ser.data
        except Exception as e:
            res.code=500
            res.error=''获取数据失败''

        return Response(res.dict)

3  序列化的使用

设置序列化为  

from rest_framework import serializers

3.1 在app中创建 serializers 的python包

serializers/course.py  设置 model中数据的 一对多,一对一,普通字段,还有选择字段的 取值序列化的展示方式

from rest_framework import serializers
from api import models
class CourseSerializer(serializers.Serializer):
    id=serializers.IntegerField()
    name=serializers.CharField()

class CourseModelSerializer(serializers.ModelSerializer):
    #(level_choices = ((0, ''初级''), (1, ''中级''), (2, ''高级''))  这种实现方式
    level_name=serializers.CharField(source=''get_level_display'')
    #一对一,一对多的实现方式
    hours=serializers.CharField(source=''coursedetail.hours'')
    #多对多的实现方式
    recommend_courses=serializers.SerializerMethodField()

    #serializers.ModelSerializer 的实现方式
    class Meta:
        model=models.Course
        fields=[''id'',''name'',''level_name'',''hours'',''recommend_courses'']

    #多对多
    def get_recommend_courses(self,row):
        recommend_list=row.coursedetail.recommend_courses.all()
        return [{''id'':item.id,''name'':item.name} for item in recommend_list]

3.2 views/course.py

在视图中取的数据后交给序列化的对象去处理

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import URLPathVersioning
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from api.serializers.course import CourseSerializer
from api.serializers.course import CourseModelSerializer
from api import models
from api.utils.response import BaseResponse


class CoursesView(APIView):

    #设置版本信息
    #versioning_class = URLPathVersioning

    def get(self,request,*args,**kwargs):
        res=BaseResponse()
        #查看版本信息
        #print(request.version)
        try:
            #方式一
            course_set=models.Course.objects.all()
            # 分页的处理
            page = PageNumberPagination()
            ser_page = page.paginate_queryset(course_set, request, self)
            #ser=CourseSerializer(instance=ser_page,many=True)
            ser = CourseModelSerializer(instance=ser_page,many=True)
            res.code=1000
            res.data=ser.data
        except Exception as e:
            res.code=500
            res.error=''获取数据失败''

        return Response(res.dict)

class CourseDetailView(APIView):

    def get(self,request,pk,*args,**kwargs):
        course_set = models.Course.objects.filter(pk=pk).first()
        # course_set_2=models.Course.objects.get(pk=pk)
        # print(type(course_set),type(course_set_2))
        ser=CourseModelSerializer(instance=course_set)
        return Response(ser.data)

 

 




Django REST framework 1

Django REST framework 1

Django REST framework

Django REST framework官方文档:点击  中文文档:点击

  1. 安装djangorestframework:pip3 install djangorestframework (pip3 list 查看详情和版本信息)
  2. 注册rest_framework(settings.py)
INSTALLED_APPS = [
    ''django.contrib.admin'',
    ''django.contrib.auth'',
    ''django.contrib.contenttypes'',
    ''django.contrib.sessions'',
    ''django.contrib.messages'',
    ''django.contrib.staticfiles'',
    ''app01'',
    ''rest_framework'',
]
settings.py

DRF序列化

做前后端分离的项目,前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式。后端给前端数据的时候都要转成json格式,那就需要对从数据库拿到的数据进行序列化。

要用DRF的序列化,就要遵循人家框架的一些标准

  1. 声明序列化类(app01目录下新建serializers.py文件)
  2. Django CBV继承类是View,现在DRF要用APIView
  3. Django中返回的时候用HTTPResponse,JsonResponse,render ,DRF用Response
  4. DRF反序列化

    • 当前端给后端发post的请求的时候,前端给后端传过来的数据,要进行一些校验然后保存到数据库。
    • 这些校验以及保存工作,DRF的Serializer也提供了一些方法了,
    • 首先要写反序列化用的一些字段,有些字段要跟序列化区分开,
    • Serializer提供了.is_valid()和.save()方法

一、Serializer

1、声明序列化类(app01中serializers.py)

from rest_framework import serializers
from .models import Book

class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)


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


book_obj = {
        "title": "Alex的使用教程",
        "w_category": 1,
        "pub_time": "2018-10-09",
        "publisher_id": 1,
        "author_list": [1, 2]
    }


data = {
    "title": "Alex的使用教程2"
}

#3.1 验证器 validators  定义函数写验证规则
def my_validate(value):
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  #required=False  不需要校验
    title = serializers.CharField(max_length=32, validators=[my_validate])  #3.2 验证器  validators用自定义的验证方法,比validate_title权重高
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)  #choices
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()
    #外键关系的序列化
    publisher = PublisherSerializer(read_only=True)  #read_only=True只序列化的时候用
    publisher_id = serializers.IntegerField(write_only=True)  #ForeignKey   #write_only=True只反序列化的时候用
    #ManyToMany的序列化
    author = AuthorSerializer(many=True, read_only=True)   #ManyToManyField
    author_list = serializers.ListField(write_only=True)
    #新建
    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data["author_list"])
        return book
    #修改
    def update(self, instance, validated_data):
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("w_category", instance.w_category)
        instance.pub_time = validated_data.get("pub_time", instance.pub_time)
        instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
        if validated_data.get("author_list"):
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance
    #验证
    #1、单个字段的验证
    def validate_title(self, value):
        if "python" not in value.lower():
            raise serializers.ValidationError("标题必须含有python")
        return value
    #2、多个字段的验证
    def validate(self, attrs):
        if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
            return attrs
        else:
            raise serializers.ValidationError("分类以及标题不符合要求")
    #3、验证器 validators
app01中serializers.py

2、用声明的序列化类去序列化(app01中views.py)

from .models import Book

from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from .serializers import BookSerializer



class BookView(APIView):
    def get(self, request):
        # book_obj = Book.objects.first()
        # ret = BookSerializer(book_obj)
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)  #多个ManyToManyField
        return Response(ret.data)


    def post(self, request):
        print(request.data)
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

class BookEditView(APIView):
    def get(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        ret = BookSerializer(book_obj)
        return Response(ret.data)

    def put(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        serializer = BookSerializer(book_obj, data=request.data, partial=True) #partial=True允许部分进行更新
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

    def delete(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        book_obj.delete()
        return Response("")
app01中views.py

二、ModelSerializer

  • 跟模型紧密相关的序列化器
  • 根据模型自动生成一组字段
  • 默认实现了.update()以及.create()方法

1、定义一个ModelSerializer序列化器(app01中serializers.py)

from rest_framework import serializers
from .models import Book

# 验证器 validators  定义函数写验证规则
def my_validate(value):
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value


class BookSerializer(serializers.ModelSerializer):
    #category = serializers.CharField(source="get_category_display",read_only=True)   #自定制
    category_display = serializers.SerializerMethodField(read_only=True)  # SerializerMethodField
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors = serializers.SerializerMethodField(read_only=True)

    def get_category_display(self, obj):
        return obj.get_category_display()

    def get_authors(self, obj):
        # obj是当前序列化的book对象
        #外键关联的对象有很多字段是用不到的~都传给前端会有数据冗余~就需要去定制序列化外键对象的哪些字段~~
        authors_query_set = obj.author.all()
        return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_query_set]

    def get_publisher_info(self, obj):
        # obj 是我们序列化的每个Book对象
        # 外键关联的对象有很多字段是用不到的~都传给前端会有数据冗余~就需要去定制序列化外键对象的哪些字段~~
        publisher_obj = obj.publisher
        return {"id": publisher_obj.id, "title": publisher_obj.title}

    class Meta:
        model = Book
        # fields = ["id", "title", "pub_time"]
        # exclude = ["user"]
        # 包含某些字段 排除某些字段
        fields = "__all__"
        # depth = 1  #depth 代表找嵌套关系的第1层
        #注意:当序列化类MATE中定义了depth时,这个序列化类中引用字段(外键)则自动变为只读
        #read_only_fields = ["id", "category_display", "publisher_info", "authors"]
        extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                        "author": {"write_only": True},"title": {"validators": [my_validate,]}}
app01中serializers.py
from rest_framework import serializers
from api import models


class CourseModelSerializer(serializers.ModelSerializer):
    # price = serializers.SerializerMethodField()
    # learn_num = serializers.SerializerMethodField()
    learn_num = serializers.IntegerField(source=''order_details.count'')
    course_detail_id = serializers.IntegerField(source=''coursedetail.id'')

    # def get_price(self, obj):
    #     # 把所有课程永久有效的价格拿出来
    #     price_obj = obj.price_policy.all().filter(valid_period=999).first()
    #     return price_obj.price

    # def get_learn_num(self, obj):
    #     return obj.order_details.count()

    # 修改序列化结果的终极方法
    def to_representation(self, instance):
        # 调用父类的同名方法把序列化的结果拿到
        data = super().to_representation(instance)
        # 针对序列化的结果做一些自定制操作
        # 判断当前这个课程是否有永久有效的价格
        price_obj = instance.price_policy.all().filter(valid_period=999).first()
        if price_obj:
            # 有永久有效的价格
            data[''has_price''] = True
            data[''price''] = price_obj.price
        else:
            # 没有永久有效的价格策略
            data[''has_price''] = False
        return data

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


class CourseCategoryModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.CourseCategory
        fields = ''__all__''
to_representation

三、Serializer和ModelSerializer的区别

四、JsonResponse和Django序列化

#app01中models.py
from django.db import models
__all__ = ["Book", "Publisher", "Author"]


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="图书名称")
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = models.IntegerField(choices=CHOICES, verbose_name="图书的类别")
    pub_time = models.DateField(verbose_name="图书的出版日期")

    publisher = models.ForeignKey(to="Publisher", on_delete=None)
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "01-图书表"
        db_table = verbose_name_plural


class Publisher(models.Model):
    title = models.CharField(max_length=32, verbose_name="出版社的名称")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "02-出版社表"
        db_table = verbose_name_plural


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者的姓名")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "03-作者表"
        db_table = verbose_name_plural

#DRFDemo中urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
    path(''admin/'', admin.site.urls),
    path(''books/'', include("SerDemo.urls")),
]
#app01中urls.py
from django.urls import path, include
from .views import BookView, BookEditView
urlpatterns = [
    path(''list'', BookView.as_view()),
    path(''retrieve/<int:id>'', BookEditView.as_view()),
]
app01中models.py 和 app01中的urls.py
#app01/views.py
from django.views import View
from django.http import HttpResponse, JsonResponse
from django.core import serializers
from .models import Book, Publisher

class BookView(View):
    #第一版 用.values JsonResponse实现序列化
    def get(self, request):
        book_list = Book.objects.values("id", "title", "category", "pub_time", "publisher")
        book_list = list(book_list)
        # 如果需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成想要的
        ret = []
        for book in book_list:
            publisher_id = book["publisher"]
            publisher_obj = Publisher.objects.filter(id=publisher_id).first()
            book["publisher"] = {
                "id": publisher_id,
                "title": publisher_obj.title
            }
            ret.append(book)
        # ret = json.dumps(book_list, ensure_ascii=False)
        # return HttpResponse(ret) #时间
        return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})

    #第二版 用django serializers实现序列化
    # 能够得到要的效果,但是结构有点复杂,而且choices不能显示对应的文本
    def get(self, request):
        book_list = Book.objects.all()
        ret = serializers.serialize("json", book_list, ensure_ascii=False)
        return HttpResponse(ret)
JsonResponse和Django序列化

DRF的视图

  • 在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等。
  • 比如,区别于Django中的request从request.GET中获取URL参数,从request.POST中取某些情况下的POST数据。
  • 在APIView中封装的request,就实现了请求数据的解析:
  • 对于GET请求的参数通过request.query_params来获取。
  • 对于POST请求、PUT请求的数据通过request.data来获取。

一、源码查找

  1. django中写CBV的时候继承的是View,rest_framework继承的是APIView
  2. 不管是View还是APIView最开始调用的都是as_view()方法。
  3. APIView继承了View, 并且执行了View中的as_view()方法,最后用csrf_exempt()方法包裹view把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。
  4. 在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法,但是这里是APIView调用的,所以先从APIView找dispatch()方法。
  5. APIView的dispatch()方法中给request重新赋值了
  6. 去initialize_request中看下把什么赋值给了request,并且赋值给了self.request, 也就是视图中用的request.xxx到底是什么
  7. 可以看到,这个方法返回的是Request这个类的实例对象,注意看下这个Request类中的第一个参数request,是走django的时候的原来的request
  8. 去Request这个类里看 这个Request类把原来的request赋值给了self._request, 也就是说以后_request是老的request,新的request是这个Request类
  9. request.query_params 存放的是get请求的参数 request.data 存放的是所有的数据,包括post请求的以及put,patch请求
  10. 相比原来的django的request,现在的request更加精简,清晰了
  11. 框架提供了一个路由传参的方法ViewSetMixin
#1.徒手垒代码阶段
class SchoolView(APIView):
    def get(self, request, *args, **kwargs):
        query_set = models.School.objects.all()
        ser_obj = app01_serializers.SchoolSerializer(query_set, many=True)
        return Response(ser_obj.data)


class SchoolDetail(APIView):
    def get(self, request, pk, *args, **kwargs):
        obj = models.School.objects.filter(pk=pk).first()
        ser_obj = app01_serializers.SchoolSerializer(obj)
        return Response(ser_obj.data)

#路由
url(r''school/$'', views.SchoolView.as_view()),
url(r''school/(?P<pk>\d+)/$'', views.SchoolDetail.as_view()),

#2.使用混合类阶段

class SchoolView(GenericAPIView, mixins.ListModelMixin):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

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


class SchoolDetail(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

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

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

#路由
url(r''school/$'', views.SchoolView.as_view()),
url(r''school/(?P<pk>\d+)/$'', views.SchoolDetail.as_view()),


# 3.使用通用类

class SchoolView(ListCreateAPIView):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer


class SchoolDetail(RetrieveUpdateDestroyAPIView):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

#路由
url(r''school/$'', views.SchoolView.as_view()),
url(r''school/(?P<pk>\d+)/$'', views.SchoolDetail.as_view()),

#4.使用视图集

class SchoolView(ModelViewSet):
    queryset = models.School.objects.all()
    serializer_class = app01_serializers.SchoolSerializer

#路由:
url(r''school/$'', views.SchoolView.as_view({
    "get": "list",
    "post": "create",
})),
url(r''school/(?P<pk>\d+)/$'', views.SchoolView.as_view({
    ''get'': ''retrieve'',
    ''put'': ''update'',
    ''patch'': ''partial_update'',
    ''delete'': ''destroy''
})),

#高级路由

from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r''school'', views.SchoolView)
urlpatterns += router.urls
视图和路由

二、ModelViewSet

from django.urls import path, include
from .views import BookView, BookEditView, BookModelViewSet
urlpatterns = [
    # path(''list'', BookView.as_view()),
    # path(''retrieve/<int:id>'', BookEditView.as_view()),
    path(''list'', BookModelViewSet.as_view({"get": "list", "post": "create"})),
    path(''retrieve/<int:pk>'', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]
app01中urls.py
from .models import Book
from .serializers import BookSerializer

from rest_framework.viewsets import ModelViewSet
class BookModelViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

#现在的视图就只要写两行就可以了
#注意:用框架封装的视图~url上的那个关键字参数要用pk系统默认的
##path(''retrieve/<int:pk>'', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}))  用pk

# from rest_framework import views
# from rest_framework import generics
# from rest_framework import mixins
# from rest_framework import viewsets
app01中views.py
from .models import Book

from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer

class GenericAPIView(APIView):
    query_set = None
    serializer_class = None

    def get_queryset(self):
        return self.query_set

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


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


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


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


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


class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        book_obj.delete()
        return Response("")


class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    pass

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

# class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
class BookView(ListCreateAPIView):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        # book_obj = Book.objects.first()
        # ret = BookSerializer(book_obj)
        # book_list = Book.objects.all()
        # book_list = self.get_queryset()
        # ret = self.get_serializer(book_list, many=True)
        # return Response(ret.data)
        return self.list(request)

    def post(self, request):
        # print(request.data)
        # serializer = BookSerializer(data=request.data)
        # if serializer.is_valid():
        #     serializer.save()
        #     return Response(serializer.data)
        # else:
        #     return Response(serializer.errors)
        return self.create(request)


# class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
class BookEditView(RetrieveUpdateDestroyAPIView):
    query_set = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # ret = BookSerializer(book_obj)
        # return Response(ret.data)
        return self.retrieve(request, id)

    def put(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # serializer = BookSerializer(book_obj, data=request.data, partial=True)
        # if serializer.is_valid():
        #     serializer.save()
        #     return Response(serializer.data)
        # else:
        #     return Response(serializer.errors)
        return self.update(request, id)

    def delete(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # book_obj.delete()
        # return Response("")
        return self.destroy(request, id)



# class ViewSetMixin(object):
#     def as_view(self):
#         """
#         按照我们参数指定的去匹配
#         get-->list
#         :return:
#         """


from rest_framework.viewsets import ViewSetMixin    #必须继承ViewSetMixin,路由的as_view方法才可以传参


class ModelViewSet(ViewSetMixin, GenericAPIView, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass


#上面封装的所有框架都帮我们封装好了
#from rest_framework.viewsets import ModelViewSet
#注意:用框架封装的视图url上的那个关键字参数要用pk系统默认的

class BookModelViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
自己封装ModelViewSet

DRF的路由

from django.urls import path, include
from .views import BookView, BookEditView, BookModelViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"book", BookModelViewSet)
urlpatterns = [
    # path(''list'', BookView.as_view()),
    # path(''retrieve/<int:id>'', BookEditView.as_view()),
    #path(''list'', BookModelViewSet.as_view({"get": "list", "post": "create"})),
    #path(''retrieve/<int:pk>'', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]
urlpatterns += router.urls

#通过框架可以把路由视图都变的非常简单
#但是需要自定制的时候还是需要用APIView写,当不需要那么多路由的时候,也不要用这种路由注册.
app01中urls.py

DRF的版本

随着项目的更新,版本就越来越多,不可能新的版本出了,以前旧的版本就不进行维护了,就需要对版本进行控制了

一、源码查找

  1. APIView返回View中的view函数,然后调用dispatch方法,APIView的dispatch方法
  2. 执行self.initial方法之前是各种赋值,包括request的重新封装赋值
    def dispatch(self, request, *args, **kwargs):
            """
            `.dispatch()` is pretty much the same as Django''s regular dispatch,
            but with extra hooks for startup, finalize, and exception handling.
            """
            self.args = args
            self.kwargs = kwargs
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                self.initial(request, *args, **kwargs)   #####
                ...
    def initial(self, request, *args, **kwargs):
                """
                Runs anything that needs to occur prior to calling the method handler.
                """
                self.format_kwarg = self.get_format_suffix(**kwargs)
    
                # Perform content negotiation and store the accepted info on the request
                neg = self.perform_content_negotiation(request)
                request.accepted_renderer, request.accepted_media_type = neg
    
                # Determine the API version, if versioning is in use.
                # 版本控制
                # self.determine_version 这个方法是找我们自己定义的版本控制类,没有的话返回(None,None)
                version, scheme = self.determine_version(request, *args, **kwargs)
                request.version, request.versioning_scheme = version, scheme
                ###version版本信息赋值给了 request.version  版本控制方案赋值给了 request.versioning_scheme
                ###其实这个版本控制方案~就是我们配置的版本控制的类,也就是说,APIView通过这个方法初始化自己提供的组件
                ###接下来看看框架提供了哪些版本的控制方法在rest_framework.versioning里,from rest_framework import versioning
    
                # Ensure that the incoming request is permitted
                # 认证 权限 频率组件
                self.perform_authentication(request)
                self.check_permissions(request)
                self.check_throttles(request)
    
    
    ...
    
        def determine_version(self, request, *args, **kwargs):
            """
            If versioning is being used, then determine any API version for the
            incoming request. Returns a two-tuple of (version, versioning_scheme)
            """
            if self.versioning_class is None:
                return (None, None)
            #scheme是我们配置的版本控制类的实例化对象
            scheme = self.versioning_class()
            #返回值scheme.determine_version  MyVersion中必须定义determine_version这个方法,从上面可以看出此方法返回版本号version
            return (scheme.determine_version(request, *args, **kwargs), scheme)
    源码查找

二、使用方法1(URL上携带版本信息的配置)

第1步:settings.py

REST_FRAMEWORK = {
    # 默认使用的版本控制类
    ''DEFAULT_VERSIONING_CLASS'': ''rest_framework.versioning.URLPathVersioning'',
    # 允许的版本
    ''ALLOWED_VERSIONS'': [''v1'', ''v2''],
    # 版本使用的参数名称
    ''VERSION_PARAM'': ''version'',
    # 默认使用的版本
    ''DEFAULT_VERSION'': ''v1'',
}
settings.py

第2步:app01中urls.py

urlpatterns = [
    url(r"^versions", MyView.as_view()),
    url(r"^(?P[v1|v2]+)/test01", TestView.as_view()),
]
app01中urls.py

第3步:测试视图app01.views.py

class TestView(APIView):
    def get(self, request, *args, **kwargs):
        print(request.versioning_scheme)
        ret = request.version
        if ret == "v1":
            return Response("版本v1的信息")
        elif ret == "v2":
            return Response("版本v2的信息")
        else:
            return Response("根本就匹配不到这个路由")
app01.views.py

三、使用方法2(URL过滤条件配置版本信息)

第1步:settings.py

REST_FRAMEWORK = {
    "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    # "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning",
    "DEFAULT_VERSION": "v1",
    "ALLOWED_VERSIONS": "v1, v2",
    "VERSION_PARAM": "ver"
}
settings.py

第2步:app01中urls.py

from django.urls import path, include
from .views import DemoView

urlpatterns = [
    path(r"", DemoView.as_view()),
]
app01中urls.py

第3步:utils中version.py

from rest_framework import versioning
class MyVersion(object):
    def determine_version(self, request, *args, **kwargs):
        # 返回值 给了request.version
        # 返回版本号
        # 版本号携带在过滤条件 xxxx?version=v1中,版本号在那就去那取值
        version = request.query_params.get("version", "v1")
        return version
utils中version.py

第4步:测试视图app01.views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class DemoView(APIView):
    def get(self, request):
        print(request.version)
        print(request.versioning_scheme)
        # 得到版本号  根据版本号的不同返回不同的信息
        if request.version == "v1":
            return Response("v1版本的数据")
        elif request.version == "v2":
            return Response("v2版本的数据")
        return Response("不存在的版本")
app01.views.py

DRF的认证

每次给服务器发请求,由于Http的无状态,导致每次都是新的请求,
服务端需要对每次来的请求进行认证,看用户是否登录,以及登录用户是谁,
服务器对每个请求进行认证的时候,不可能在每个视图函数中都写认证,
一定是把认证逻辑抽离出来,以前我们可能会加装饰器或者中间件。

一、源码查找

def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django''s regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

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

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

...
    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )


    def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        # 版本控制
        # self.determine_version 这个方法是找我们自己定义的版本控制类,没有的话返回(None,None)
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        # 认证 权限 频率组件
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)

...
    def perform_authentication(self, request):
        """
        Perform authentication on the incoming request.

        Note that if you override this and simply ''pass'', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        """
        request.user
...
#去类Request中找user        

    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, ''_user''):
            with wrap_attributeerrors():
                #__enter__
                self._authenticate()
                #__exit__
        return self._user
...

    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        #这里的authentications是最开始实例化Request类的时候传过来的
        #是调用get_authenticators这个方法,
        # 这个方法的返回值是 return [auth() for auth in self,authentication_classes]
        #authentication_classes如果我们配置了就用我们配置的,否则就从默认配置文件中读取配置类
        #返回的auth()是认证类实例化后的
        for authenticator in self.authenticators:   #查看authenticators
            try:
                #也就是说这里的authenticator是认证类实例化后的
                #authenticate方法是我们必须去实现的方法
                #authenticate的参数self,我们是通过新的request.user进来的,所以这个self就是新的request
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

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

        self._not_authenticated()

...
class Request(object):

    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        assert isinstance(request, HttpRequest), (
            ''The `request` argument must be an instance of ''
            ''`django.http.HttpRequest`, not `{}.{}`.''
            .format(request.__class__.__module__, request.__class__.__name__)
        )

        self._request = request
        self.parsers = parsers or ()
        self.authenticators = authenticators or ()
        ## authenticators看传参了么
...

    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),  #传参了
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

...

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        #self.authentication_classes去配置文件拿所有的认证类
        return [auth() for auth in self.authentication_classes]
源码查找
  • APIView的dispatch方法里给request重新赋值了
  • APIView的dispatch方法里给执行了initial方法,初始化了版本认证,权限,频率组件,initial方法的参数request是重新赋值后的
  • 权限组件返回的是request.user,initial的request是重新赋值之后的,所以这里的request是重新赋值之后的,也就是Request类实例对象, 那这个user一定是一个静态方法.

二、使用方法

1、app01中models.py

# 先在model中注册模型类
# 并且进行数据迁移

from django.db import models

class User(models.Model):

    username = models.CharField(max_length=32)
    pwd = models.CharField(max_length=16)
    token = models.UUIDField()
app01中models.py

2、app01中urls.py

from django.urls import path
from .views import DemoView, LoginView, TestView


urlpatterns = [
    path(r"login", LoginView.as_view()),
    path(r"test", TestView.as_view()),
]
app01中urls.py

3、app01中views.py

import uuid
from .models import User
from utils.auth import MyAuth

from rest_framework.views import APIView
from rest_framework.response import Response

class LoginView(APIView):

    def post(self, request):
        username = request.data.get("username")
        pwd = request.data.get("pwd")
        # 登录成功 生成token 会把token给你返回
        token = uuid.uuid4()
        User.objects.create(username=username, pwd=pwd, token=token)
        return Response("创建用户成功")

#局部视图认证
class TestView(APIView):
    authentication_classes = [MyAuth,]

    def get(self, request):
        print(request.user)
        print(request.auth)
        user_id = request.user.id
        return Response("认证测试")
app01中views.py

4、utils中auth.py 写一个认证的类

from rest_framework.exceptions import AuthenticationFailed
from app01.models import User
from rest_framework.authentication import BaseAuthentication


class MyAuth(BaseAuthentication):

    def authenticate(self, request):
        # 做认证 看他是否登录
        # 拿到token,此处是从url过滤条件里拿到token
        # 去数据库看token是否合法
        # 合法的token能够获取用户信息
        token = request.query_params.get("token", "")
        if not token:
            raise AuthenticationFailed("没有携带token")
        user_obj = User.objects.filter(token=token).first()
        if not user_obj:
            raise AuthenticationFailed("token不合法")
        # return (None, None)  
        return (user_obj, token) #第1个返回值是request.user 第2个返回值是request.auth
utils中auth.py

5、全局配置认证

REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning",
    "DEFAULT_VERSION": "v1",
    "ALLOWED_VERSIONS": "v1, v2",
    "VERSION_PARAM": "ver",
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]  #全局配置
}
settings.py

DRF的权限

对某件事情决策的范围和程度叫做权限

一、源码查找

def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        for permission in self.get_permissions():
            #permission我们写的权限类的实例对象 MyPermission()
            if not permission.has_permission(request, self):
                #permission_denied是抛出异常的
                #也就是说我们的权限类中必须有has_permission这个方法,否则就抛出异常
                self.permission_denied(
                     #message 定义异常信息
                    request, message=getattr(permission, ''message'', None)
                )
源码查找
  • 权限类一定要有has_permission方法,否则就会抛出异常,这也是框架提供的钩子
  • rest_framework.permissions这个文件中存放了框架提供的所有权限的方法
  • BasePermission 这个是写权限类继承的一个基础权限类
  • Python代码是一行一行执行的,那么执行initial方法初始化这些组件的时候 也是有顺序的,版本在前面然后是认证,然后是权限最后是频率
  • 版本,认证,权限,频率这几个组件的源码是一个流程

二、使用方法

1、app01中models.py

# 先在model中注册模型类
# 并且进行数据迁移

from django.db import models

class User(models.Model):

    username = models.CharField(max_length=32)
    pwd = models.CharField(max_length=16)
    token = models.UUIDField()
    type = models.IntegerField(choices=((1, "vip"), (2, "vvip"), (3, "普通")), default=3)
app01中models.py

2、app01中urls.py

from django.urls import path
from .views import DemoView, LoginView, TestView


urlpatterns = [
    path(r"login", LoginView.as_view()),
    path(r"test", TestView.as_view()),
]
app01中urls.py

3、app01中views.py

import uuid
from .models import User
from utils.auth import MyAuth
from utils.permission import MyPermission
# Create your views here.

from rest_framework.views import APIView
from rest_framework.response import Response


class DemoView(APIView):
    def get(self, request):
        return Response("认证demo~")


class LoginView(APIView):

    def post(self, request):
        username = request.data.get("username")
        pwd = request.data.get("pwd")
        # 登录成功 生成token 会把token给你返回
        token = uuid.uuid4()
        User.objects.create(username=username, pwd=pwd, token=token)
        return Response("创建用户成功")


class TestView(APIView):
    authentication_classes = [MyAuth,]
    permission_classes = [MyPermission, ]  #局部配置权限

    def get(self, request):
        print(request.user)
        print(request.auth)
        user_id = request.user.id
        return Response("认证测试")
app01中views.py

4、utils中permission.py 写一个权限类

from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    message = "您没有权限"

    def has_permission(self, request, view):
        # 判断用户是否有权限
        user_obj = request.user
        if user_obj.type == 3:
            return False
        else:
            return True
utils中permission.py

5、全局配置权限

REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning",
    "DEFAULT_VERSION": "v1",
    "ALLOWED_VERSIONS": "v1, v2",
    "VERSION_PARAM": "ver",
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]  #全局配置
}
REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    # 默认使用的版本控制类
    ''DEFAULT_VERSIONING_CLASS'': ''rest_framework.versioning.URLPathVersioning'',
    # 允许的版本
    "ALLOWED_VERSIONS": "v1, v2",
    # 版本使用的参数名称
     "VERSION_PARAM": "ver",
    # 默认使用的版本
    ''DEFAULT_VERSION'': ''v1'',
    # 配置全局认证
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]  #全局配置
    # 配置全局权限
    "DEFAULT_PERMISSION_CLASSES": ["utils.permission.MyPermission"]
}
settings.py

DRF的频率

开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用。

一、源码查找

def check_throttles(self, request):
        """
        Check if request should be throttled.
        Raises an appropriate exception if the request is throttled.
        """
        #throttle 配置每个频率控制类的实例化对象   allow_request方法和wait方法
        for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                self.throttled(request, throttle.wait())

...
    def get_throttles(self):
        """
        Instantiates and returns the list of throttles that this view uses.
        """
        return [throttle() for throttle in self.throttle_classes]
源码查找

二、频率组件原理

DRF中的频率控制基本原理是基于访问次数和时间的,当然也可以通过自己定义的方法来实现。

当请求进来,走到频率组件的时候,DRF内部会有一个字典来记录访问者的IP,

以这个访问者的IP为key,value为一个列表,存放访问者每次访问的时间,

{  IP1: [第三次访问时间,第二次访问时间,第一次访问时间],}

把每次访问最新时间放入列表的最前面,记录这样一个数据结构后,通过什么方式限流呢~~

如果我们设置的是10秒内只能访问5次,

  -- 1,判断访问者的IP是否在这个请求IP的字典里

  -- 2,保证这个列表里都是最近10秒内的访问的时间

      判断当前请求时间和列表里最早的(也就是最后的)请求时间的查

      如果差大于10秒,说明请求以及不是最近10秒内的,删除掉,

      继续判断倒数第二个,直到差值小于10秒

  -- 3,判断列表的长度(即访问次数),是否大于我们设置的5次,

      如果大于就限流,否则放行,并把时间放入列表的最前面。

三、使用方法

1、app01中views.py

import uuid
from .models import User
from utils.auth import MyAuth
from utils.permission import MyPermission
from utils.throttle import MyThrottle
# Create your views here.

from rest_framework.views import APIView
from rest_framework.response import Response

class LoginView(APIView):

    def post(self, request):
        username = request.data.get("username")
        pwd = request.data.get("pwd")
        # 登录成功 生成token 会把token给你返回
        token = uuid.uuid4()
        User.objects.create(username=username, pwd=pwd, token=token)
        return Response("创建用户成功")


class TestView(APIView):
    authentication_classes = [MyAuth,]
    permission_classes = [MyPermission, ]
    throttle_classes = [MyThrottle, ]

    def get(self, request):
        print(request.user)
        print(request.auth)
        user_id = request.user.id
        return Response("认证测试")
app01中views.py

2、utils中throttle.py 写一个频率类

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
import time

VISIT_RECORD = {}

#自定义的频率限制类

# class MyThrottle(BaseThrottle):
#
#     def __init__(self):
#         self.history = None
#
#     def allow_request(self, request, view):
#         # 实现限流的逻辑
#         # 以IP限流
#         # 访问列表 {IP: [time1, time2, time3]}
#         # 1, 获取请求的IP地址
#         ip = request.META.get("REMOTE_ADDR")
#         # 2,判断IP地址是否在访问列表
#         now = time.time()
#         if ip not in VISIT_RECORD:
#             # --1, 不在 需要给访问列表添加key,value
#             VISIT_RECORD[ip] = [now,]
#             return True
#             # --2 在 需要把这个IP的访问记录 把当前时间加入到列表
#         history = VISIT_RECORD[ip]
#         history.insert(0, now)
#         # 3, 确保列表里最新访问时间以及最老的访问时间差 是1分钟
#         while history and history[0] - history[-1] > 60:
#             history.pop()
#         self.history = history
#         # 4,得到列表长度,判断是否是允许的次数
#         if len(history) > 3:
#             return False
#         else:
#             return True
#
#     def wait(self):
#         # 返回需要再等多久才能访问
#         time = 60 - (self.history[0] - self.history[-1])
#         return time

#使用自带的频率限制类
class MyThrottle(SimpleRateThrottle):
    scope = "WD"

    def get_cache_key(self, request, view):
        # 如果以IP地址做限流返回IP地址
        key = self.get_ident(request)
        return key
utils中throttle.py

3、全局配置频率

REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning",
    "DEFAULT_VERSION": "v1",
    "ALLOWED_VERSIONS": "v1, v2",
    "VERSION_PARAM": "ver",
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]  #全局配置
}
REST_FRAMEWORK = {
    # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
    # 默认使用的版本控制类
    ''DEFAULT_VERSIONING_CLASS'': ''rest_framework.versioning.URLPathVersioning'',
    # 允许的版本
    "ALLOWED_VERSIONS": "v1, v2",
    # 版本使用的参数名称
     "VERSION_PARAM": "ver",
    # 默认使用的版本
    ''DEFAULT_VERSION'': ''v1'',
    # 配置全局认证
    # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]  #全局配置
    # 配置全局权限
    "DEFAULT_PERMISSION_CLASSES": ["utils.permission.MyPermission"],
    # 配置自定义频率限制
    "DEFAULT_THROTTLE_CLASSES": ["Throttle.throttle.MyThrottle"],
    # 配置频率限制
    "DEFAULT_THROTTLE_RATES": {
        "WD": "3/m"   #速率配置每分钟不能超过3次访问,WD是scope定义的值,
    }
}
settings.py

DRF的分页组件

  • DRF提供的三种分页: from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
  • 全局配置: REST_FRAMEWORK = { ''PAGE_SIZE'': 2 }
  • 第1种 PageNumberPagination 看第n页,每页显示n条数据 http://127.0.0.1:8000/book?page=2&size=1
  • 第2种 LimitOffsetPagination 在第n个位置 向后查看n条数据 http://127.0.0.1:8000/book?offset=2&limit=1
  • 第3种 CursorPagination 加密游标的分页 把上一页和下一页的id记住 http://127.0.0.1:8000/book?page=2&size=1

一、utils中pagination.py(自定义分页类)

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination

# class MyPagination(PageNumberPagination):
#     # xxxx?page=1&size=2
#     page_size = 1  # 每页显示多少条
#     page_query_param = "page"   # URL中页码的参数
#     page_size_query_param = "size"  # URL中每页显示条数的参数
#     max_page_size = 3    # 最大页码数限制

# class MyPagination(LimitOffsetPagination):
#
#     default_limit = 1
#     limit_query_param = "limit"
#     offset_query_param = "offset"
#     max_limit = 3

class MyPagination(CursorPagination):

    cursor_query_param = "cursor"
    page_size = 2
    ordering = "-id"
utils中pagination.py

二、app01中views.py

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from SerDemo.models import Book
from SerDemo.serializers import BookSerializer

# Create your views here.
from rest_framework import pagination
from utils.pagination import MyPagination
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin


# class BookView(APIView):
#
#     def get(self, request):
#         queryset = Book.objects.all()
#         # 1,实例化分页器对象
#         page_obj = MyPagination()
#         # 2,调用分页方法去分页queryset
#         page_queryset = page_obj.paginate_queryset(queryset, request, view=self)
#         # 3,把分页好的数据序列化返回
#         # 4, 带着上一页下一页连接的响应
#         ser_obj = BookSerializer(page_queryset, many=True)
#         # 返回带超链接 需返回的时候用内置的响应方法
#         return page_obj.get_paginated_response(ser_obj.data)


class BookView(GenericAPIView, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = MyPagination
    # self.paginate_queryset(queryset)

    def get(self, request):
        return self.list(request)
app01中views.py

DRF的解析器

  • 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己想要的数据类型的过程。本质就是对请求体中的数据进行解析。
  • 在了解解析器之前要先知道Accept以及ContentType请求头。
  • Accept是告诉对方能解析什么样的数据,通常也可以表示想要什么样的数据。
  • ContentType是告诉对方我给你的是什么样的数据类型。
  • 解析器工作原理的本质 就是拿到请求的ContentType来判断前端给后端数据类型是什么,然后后端去拿相应的解析器去解析数据。

一、Django的解析器

  • 请求进来请求体中的数据在request.body中,那也就证明,解析器会把解析好的数据放入request.body
  • 在视图中可以打印request的类型,能够知道request是WSGIRequest这个类。
  • application/x-www-form-urlencoded不是不能上传文件,是只能上传文本格式的文件
  • multipart/form-data是将文件以二进制的形式上传,这样可以实现多种类型的文件上传 一个解析到request.POST, request.FILES中。
  • 也就是说之前能在request中能到的各种数据是因为用了不同格式的数据解析器
  • Django只能解析cont_type=multipart/form-data 和cont_type=application/x-www-form-urlencoded的数据,不能解析json

二、DRF的解析器

  • 在request.data拿数据的时候解析器会被调用

四、DRF的解析器使用方法

1、app01中views.py

from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
from django.core.handlers.wsgi import WSGIRequest
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.negotiation import DefaultContentNegotiation
from rest_framework import parsers

# Create your views here.


class DjangoView(View):
    def get(self, request):
        print(type(request))
        # Request
        # request.GET
        # request.POST
        # json request.body
        return HttpResponse("django解析器测试~~")


class DRFView(APIView):
    #parser_classes = [parsers.JSONParser, ]  #一般不配置

    def get(self, request):
        # request 重新封装的request  Request
        # request.data
        #
        return Response("DRF解析器的测试~~")
app01中views.py

DRF的渲染器

渲染器就是友好的展示数据,我们在浏览器中展示的DRF测试的那个页面就是通过浏览器的渲染器来做到的,当然我们可以展示Json数据类型

DEFAULTS = {
    # Base API policies
    ''DEFAULT_RENDERER_CLASSES'': (
        ''rest_framework.renderers.JSONRenderer'',
        ''rest_framework.renderers.BrowsableAPIRenderer'',
    ),
DRF的渲染器

Django REST framework 中依赖于格式的字段表示

Django REST framework 中依赖于格式的字段表示

如何解决Django REST framework 中依赖于格式的字段表示?

在 Django REST 框架中,我需要根据所选的显示格式(渲染器)对字段的 value 进行不同的字符串表示。查看 custom fields 的 to_representation()to_internal_values() 方法的参数,这是不可能开箱即用的。这可以使用标准 DRF 工具完成吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

今天关于从Django Rest Framework响应中删除空字段django删除项目的讲解已经结束,谢谢您的阅读,如果想了解更多关于Django - rest - framework - 下、django rest framework、Django REST framework 1、Django REST framework 中依赖于格式的字段表示的相关知识,请在本站搜索。

本文标签: