Django REST framework框架

rest-framework框架主要帮助我们快速开发rest-framework接口,就算没有这个框架我们也可以实现这些功能,但是经过框架的封装,会更加简洁、方便。

1、APIView

Django的rest-framework框架都是基于CBV来完成的,首先来了解一下CBV的执行流程

 CBV执行流程

1、创建url

 2、创建视图类

3、as_view方法源码

 因为我们自定义的试图类都会继承View类,所以启动项目的时候,url中的as_view函数就会执行,在我们自定义的函数类中没有这个方法就会到父类中去找

 4、view函数

 5、dispatch

 

 6、补充(http_method_names)

url中视图函数中的执行 

# url(r'^login/', views.LoginView.as_view()), 
# url(r'^login/', View.as_view()), 
# url(r'^login/', View.view),

APIView执行源码解析

使用APIView的大概流程与正常的CBV流程是差不多的,但是在一些关键方法APIView会有一些添加的代码,自定义自己的方法

1、定义url

这一步与使用View的CBV是一样的

2、定义视图类

3、查看APIView类中的as_view

APIView还是继承view类的,但会有一些自定义的方法

 

4、APIView自己的dispatch

由于as_view方法也是继承的父类View的as_view方法,所以接下来的流程都是一样,只不过,当在执行dispatch方法的时候它执行的APIView自己的实例方法

APIView 的url视图函数的执行

     #url(r'^publishes/', views.PublishView.as_view()),
     #url(r'^publishes/', APIView.as_view()),
     #url(r'^publishes/', View.view),

2、序列化组件

序列化组件主要就是将queryset序列化成JSON

Django框架内置序列化组件

from django.core.serializers import serialize

使用方式

publish_list=Publish.objects.all()
ret=serialize("json",publish_list)

 rest-framework中的序列化组件

from rest_framework import serializers

方式一:自定义序列化组件Serializer

model部分:

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)

    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author',)

    def __str__(self):
        return self.title

view部分:

class BookSerializers(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.CharField()
    publishDate=serializers.DateField()

    #   针对一对多
    publish=serializers.CharField(source="publish.name")
    publish_email=serializers.CharField(source="publish.email")
    #   针对多对多
    authors=serializers.SerializerMethodField()
    def get_authors(self,obj):
        data=[]
        for i in obj.authors.all():
            temp=[]
            temp.append(i.pk)
            temp.append(i.name)
            data.append(temp)
        return data

我们自定义的BookSerializers组件是一个集成的功能组件,到底用什么功能,取决于调用什么接口

补充:

settings.py文件配置

APPEND_SLASH = False  # 在访问url路径的时候必须在最后面加上斜线,不加会报错。默认这个属性为True,在访问url如果不加最后的那个斜线就会自动带上斜线重新访问一次

方式二:ModelSerializer

 ModelSerializer跟Django中的ModelForm是类似的,它和我们自定义使用的Serializer是相同的,但是提供了一系列已经封装好的功能与方法

1、基于模型类生成一系列的字符串

2、基于模型类自动为Serializer生成validators,比如unique_together

3、包含默认的create()和update()的实现

定义:

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book         # 对应模型类
        fields = "__all__"   # 展示所有字段

从上面的代码可以看到,这个与Django的modelform的定义方式是一模一样的

序列化功能实现

    # 序列化多条记录
    book_list = Book.objects.all()
    ps = BookSerializers(book_list, many=True)

    #   指定序列化记录                    
    book_obj=Book.objects.filter(pk=pk).first()
    bs=BookSerializers(book_obj,many=False)

    # 当我们要序列化一个queryset或者一个列表的时候就应该将参数 many=Ture,
    # 序列化单个对象实例时应该将参数 many=False

校验字段和操作记录

# 添加数据
bs=BookSerializers(data=request.data)
if bs.is_valid():     #校验字段接口
    bs.save()     # 生成记录接口
    return Response(bs.data)     # 序列化接口    
    
    
# 更新数据    
bs=BookSerializers(data=request.data,instance=book_obj)
if bs.is_valid():     #校验字段接口
    bs.save()     #更新记录接口
    return Response(bs.data)     # 序列化接口    

3、视图

在rest-framework中的视图都是基于类的视图。REST framework 提供了一个 APIView 类,它继承于 Django 的 View 类。

APIView类与View类的区别:

  1、传递给处理方法的 request 对象是 REST framework 的 Request 实例,而不是 Django 的 HttpRequest 实例。

  2、处理方法可能返回 REST framework 的 Response,而不是 Django 的 HttpResponse 。该视图将管理内容协商,并在响应中设置正确的渲染器。

  3、任何 APIException 异常都会被捕获并进行相应的响应。

  4、传入的请求会进行认证,在请求分派给处理方法之前将进行适当的权限检查(允许或限制)。

APIView类和View的常规使用非常的相似,将不同的请求分配到不同的方法当中,如:“get”,“post”等。除了这些请求方式,还可以在类中设置一些属性

(1)基础版:

class BookView(APIView):

    def get(self,request):
        book_list = Book.objects.all()
        bs = BookSerializers(book_list, many=True)
        return Response(bs.data)

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

class BookDetailView(APIView):

    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        bs = BookSerializers(book, many=False)
        return Response(bs.data)

    def put(self, request, pk):
        book_obj = Book.objects.filter(pk=pk).first()
        bs = BookSerializers(data=request.data, instance=book_obj)
        if bs.is_valid():
            bs.save()
            print(bs.data)
            return Response(bs.data)
        else:
            return Response(bs.errors)

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

从上面的代码我们可以看出没个请求方法就会走对应方法名的函数。但是这种方式当我们有大量处理数据的模型表的时候,每一个都要这样写的话就会造成一定的代码冗余,因为中间有大量的重复代码,这就需要对这个重复代码进行整合调整,减少代码冗余。

(2)升级版:

为了减少代码的冗余在rest-framework框架当中已经帮我们封装好了各个请求方法的功能类

from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin

各个类的功能:

CreateModelMixin:提供 .create(request, *args, **kwargs) 方法,实现创建和保存新模型实例。如果创建了一个对象,则返回一个201 Created响应,该对象的序列化表示形式作为响应的主体。如果表示包含名为的键url,则Location响应的标题将填充该值。
如果为创建对象而提供的请求数据无效,则将返回响应400 Bad Request,并将错误详细信息作为响应的主体。

ListModelMixin:提供一个 .list(request, *args, **kwargs) 方法,实现了列出一个查询集。如果填充了查询集,则返回200 OK响应,并将查询集的序列化表示形式作为响应的主体。可选地,可以对响应数据进行分页。

DestroyModelMixin:提供一种.destroy(request, *args, **kwargs)实现删除现有模型实例的方法。如果删除了一个对象,则返回一个204 No Content响应,否则返回一个404 Not Found。

RetrieveModelMixin:提供 .retrieve(request, *args, **kwargs) 方法,该方法实现在响应中返回现有的模型实例。如果可以检索对象,则返回200 OK响应,并将对象的序列化表示作为响应的主体。否则它会返回一个404 Not Found。

UpdateModelMixin:提供.update(request, *args, **kwargs)实现更新和保存现有模型实例的方法。
还提供了.partial_update(request, *args, **kwargs)一种类似于该update方法的方法,只是更新的所有字段都是可选的。允许支持HTTP PATCH请求。如果更新了对象,则返回200 OK响应,并将对象的序列化表示作为响应的主体。
如果为更新对象而提供的请求数据无效,400 Bad Request则将返回响应,并将错误详细信息作为响应的主体。

上面调用的各个类分别都封装了对应的请求处理方式

from rest_framework.generics import GenericAPIView

所有通用视图类的基类,继承APIView类

逻辑代码:

class AuthorView(CreateModelMixin,ListModelMixin,GenericAPIView,):

        queryset=Author.objects.all
        serializer_class=AuthorSerializers

        def get(self,request):
            return self.list(request)
        def post(self,request):
            return self.create(request)
            
class AuthorDetailView(DestroyModelMixin,UpdateModelMixin,RetrieveModelMixin,GenericAPIView,):
        queryset = Author.objects.all
        serializer_class = AuthorSerializers

        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)

上面的代码相对于最开始的方法来说显得更加紧凑,减少了很多的冗余代码,但是看上去还是有很多的代码,怎么办? 有办法,在rest-framework框架中已经封装好功能更加健全的类

必须参数:
queryset - 用于从此视图返回对象的查询集。
serializer_class - 用于验证和反序列化输入以及序列化输出的序列化类。

(3)高级版:

在这两个类中将各类请求方法中公共的逻辑都已经封装好了

class AuthorView(generics.ListCreateAPIView):

    queryset=Author.objects.all
    serializer_class=AuthorSerializers

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

看到上面的代码已经这么精简了,比之前的要少很多了,可能觉得已经结束了,可以仔细看一下上面的代码,两个类都是对一个模型类进行操作,为什么不将这两个类合并到一起呢。

合并可以,但是有一个很严重的问题,因为这两个类分别有一个url,而且两个url是不同的

    url(r'^authors/$', views.AuthorModelView.as_view()),
    url(r'^authors/(?P<pk>\d+)/$', views.AuthorModelView.as_view())

一个是没有参数的,是针对所有的数据进行操作,第二个url后面是会跟上对应的某条记录对应的id,是针对某一条记录进行操作的。

(4)最终版:

超级无敌的封装类 ↓

from rest_framework.viewsets import ModelViewSet

视图类:

class AuthorModelView(ModelViewSet):

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

对应url:

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

看到上面的代码,肯定可以发现新的url与之前的url的区别,在新的url中的as_view函数中都带有参数,参数中是一个字典,带着一个一个键值对。每一个请求方法都对应一个值,这个需要注意。

当视图类继承ModelViewSet之后对应的url所执行的as_view方法就不再是APIView类中的as_view了,而是一个新的as_view方法了

在这个新的as_view方法当中由action来接收对应的字典参数。

看一看新的view函数

执行完这个view函数,会发现最后还是返回的dispatch函数的执行结果,而且这个dispatch还是APIView的dispatch。所以绕来绕去最终还是会到APIView中的dispatch函数中执行。

4、解析器(Parser)

 REST框架包括许多内置的Parser类,允许接受具有各种媒体类型的请求。也支持定义您自己的定制解析器,这使您能够灵活地设计您的API所接受的媒体类型。

如何确定解析器

视图的有效解析器集总是被定义为类的列表。当 request.data被访问时,REST框架将检查Content-Type对传入的请求头,并确定要使用到解析请求其内容解析器。

注意:

在开发客户端应用程序时,请始终记住确保Content-Type在HTTP请求中发送数据时设置标头。
如果您未设置内容类型,则大多数客户端将默认使用'application/x-www-form-urlencoded',但是这肯定不是我们需要的,
例如,如果json使用带有.ajax()方法的 jQuery 发送编码数据,则应确保包含该contentType: 'application/json'设置。

设置解析器

在设置解析器之前我们先来了解一波内置的解析器配置

为了是我们的解析器是JSON格式的,就需要在当前项目的settings.py文件下做如下配置:

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
    )
}

这是一个全局的设置,以下设置仅允许具有JSON内容的请求,而不是默认的JSON或表单数据。

我们还可以使用APIView设置用于单个视图或视图集的解析器。

解析器API参考:

JSONParser:
解析JSON请求内容。
.media_type:application/json

FormParser:
解析HTML表单内容。 
request.data将填充QueryDict一些数据。
通常希望同时使用FormParser,MultiPartParser以便完全支持HTML表单数据。
.media_type:application/x-www-form-urlencoded

MultiPartParser:
解析多部分HTML表单内容,支持文件上载。
两者都request.data将填充QueryDict。
通常希望同时使用FormParser,MultiPartParser以便完全支持HTML表单数据。
.media_type:multipart/form-data

FileUploadParser:
解析原始文件上传内容。该request.data属性将是一个'file'包含上传文件的单个字典的字典。如果所使用的视图FileUploadParser是带一个filenameURL关键字参数,则该参数将被用作文件名。
如果在没有filenameURL关键字参数的情况下调用它,则客户端必须在Content-DispositionHTTP标头中设置文件名。例如Content-Disposition: attachment; filename=upload.jpg。
.media_type:*/*

5、认证

认证就是将传入的请求与一组标识凭证关联起来的机制(例如来自用户的请求或其签名的令牌)相关联的机制。许可和节流策略可以使用这些凭证来确定是否应该允许请求。

REST框架提供了大量的认证方案,并且允许自己实现自定义方案。身份认证都是最先运行的,在发生权限和限制检查之前,并且在任何其他代码被允许进行之前。

request.user属性通常将设置为contrib.auth包的User类的实例。

request.auth属性用于任何其他身份验证信息,例如,它可用于表示请求已签名的身份验证令牌。

注意:

不要忘记身份验证本身不允许或禁止传入请求,它只是标识请求所使用的凭据。

了解过上面几种rest-framework框架的几个特性后,肯定会对APIView中的dispatch方法特别熟悉,因为对数据的序列化归根结底最后都得走这个方法。就算是认证也会经过dispatch方法。

认证、权限、频率这三个特性都写在一切,而且执行顺序也是依次从上到下的,所以如果不经过验证的话,以下的功能都无法执行。

现在,就进入认证功能里面看看具体执行那些代码。

在dispatch方法中对request有过封装

点进去看看

 到此就是整个认证功能的流程,了解完这个,就可以具体进行操作

view.py

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):
        res = {"code": 1000,"msg": None}
        try:
            name = request.data.get("name")
            pwd = request.data.get("pwd")
            user_obj = User.objects.filter(name=name,pwd=pwd).first()
            print(name,pwd,user_obj)
            if not user_obj:
                res["code"] = 1001
                res['msg'] = "用户名或密码错误"
            else:
                token = get_random_str(name)
                UserToken.objects.update_or_create(user=user_obj,defaults={"token":token})
                res["token"] = token
        except Exception as e:
            res["code"] = 1002
            res['msg'] = str(e)
        return JsonResponse(res, json_dumps_params={"ensure_ascii":False})

auth.py

from app02.models import UserToken
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication

class Authentication(BaseAuthentication):

    def authenticate(self,request):
        token = request.GET.get("token",None)
        token_obj = UserToken.objects.filter(token=token).first()
        if token_obj:
            return token_obj.user.name,token_obj
        else:
            raise AuthenticationFailed("认证失败!")

配置:

全局配置:

# 在settings.py文件下
DEFAULTS = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    ),
}

局部配置:

# 在需要认证功能的视图类中加上属性authentication_classes ,参数就是编写的自定义认证功能的类名
authentication_classes = [Authentication,]

6、权限

单单使用认证功能的话,并不能得到用户的信息以及对代码的访问权限。所以,对于这些数据请求必须拥有授权才可以。

权限功一般都是和认证功能结合一起使用的,都是在执行正式的代码之前执行的,但是在上面的源码可以看到,认证功能是在权限之上的,所以必须通过认证之后才会执行权限功能,确认权限。权限检查通常使用request.userrequest.auth属性中的身份验证信息来确定是否应允许传入请求。

权限用于授予或拒绝不同类别的用户访问API的不同部分。

最简单的权限类型是允许访问任何经过身份验证的用户,并拒绝访问任何未经身份验证的用户。这对应IsAuthenticated于REST框架中的类。

如何确定权限

REST框架中的权限始终定义为权限类列表。

在运行视图的主体之前,将检查列表中的每个权限。如果有任何权限检查失败的情况exceptions.PermissionDeniedexceptions.NotAuthenticated将引发异常,并且视图的主体将无法运行。

当权限检查失败时,将返回“403 Forbidden”或“401 Unauthorized”响应,根据以下规则:

  • 请求已成功通过身份验证,但权限已被拒绝。 - 将返回HTTP 403 Forbidden响应。
  • 请求未成功通过身份验证,并且优先级最高的身份验证类使用WWW-Authenticate标头。 - 将返回HTTP 403 Forbidden响应。
  • 请求未成功通过身份验证,并且优先级最高的身份验证类确实使用WWW-Authenticate标头。WWW-Authenticate将返回带有适当标头的HTTP 401 Unauthorized响应。

权限功能与认证功能所走的流程是一样的,只是在最后执行具体功能的区别

在其中的get_permissions()方法中就是将我们自定定义的配置信息通过一个列表推导式返回

具体操作:

permissions.py文件

class Permission(object):

    message = "没有访问权限!"
    def has_permission(self, request, view):
        user_type = request.auth.user.type
        if user_type == 3:
            return True
        else:
            return False

配置:

# 全局配置
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES':[
        'app02.utils.permissions.Permission'    # 自定义权限类路径
    ],

局部配置

# 在需要添加权限组件的试图类中添加
permission_classes = [Permission,]

API参考

AllowAny
该AllowAny许可类将允许不受限制的访问,不管请求被认证或未认证的。

此权限不是严格要求的,因为您可以通过使用空列表或元组进行权限设置来获得相同的结果,但您可能会发现指定此类很有用,因为它使意图明确。

IsAuthenticated
该IsAuthenticated许可类将拒绝允许任何未认证用户,并允许许可,否则。

如果您希望您的API仅供注册用户访问,则此权限适用。

IsAdminUser
所述IsAdminUser许可类将拒绝许可给任何用户,除非user.is_staff是True在这种情况下的许可将被允许。

如果您希望只有可信管理员的子集可以访问您的API,则此权限是合适的。

IsAuthenticatedOrReadOnly
这IsAuthenticatedOrReadOnly将允许经过身份验证的用户执行任何请求。只有在请求方法是“安全”方法之一时,才允许对未经授权的用户提出请求; GET,HEAD或OPTIONS。

如果您希望API允许匿名用户具有读取权限,并且仅允许对经过身份验证的用户具有写入权限,则此权限是合适的。

DjangoModelPermissions
此权限类与Django的标准django.contrib.auth 模型权限相关联。此权限只能应用于具有.queryset属性集的视图。只有在用户通过身份验证且分配了相关的模型权限后,才会授予授权。

POST请求要求用户拥有add模型的权限。
PUT和PATCH请求要求用户拥有change模型的权限。
DELETE请求要求用户拥有delete模型的权限。
还可以重写默认行为以支持自定义模型权限。例如,您可能希望包含请求的view模型权限GET。

要使用自定义模型权限,请覆盖DjangoModelPermissions并设置.perms_map属性。有关详细信息,请参阅源代码。

使用不包含queryset属性的视图。
如果您对使用重写get_queryset()方法的视图使用此权限,则视图上可能没有queryset属性。在这种情况下,我们建议使用sentinel查询集标记视图,以便此类可以确定所需的权限。例如:

queryset = User.objects.none()  # Required for DjangoModelPermissions
DjangoModelPermissionsOrAnonReadOnly
与此类似DjangoModelPermissions,但也允许未经身份验证的用户具有对API的只读访问权限。

DjangoObjectPermissions
此权限类与Django的标准对象权限框架相关联,该框架允许模型上的每个对象权限。要使用此权限类,您还需要添加支持对象级权限的权限后端,例如django-guardian。

与DjangoModelPermissions此一样,此权限只能应用于具有.queryset属性或.get_queryset()方法的视图。只有在用户通过身份验证且具有相关的每个对象权限和相关的模型权限时,才会授予授权。

POST请求要求用户拥有add模型实例的权限。
PUT和PATCH请求要求用户拥有change模型实例的权限。
DELETE请求要求用户拥有delete模型实例的权限。
请注意,DjangoObjectPermissions 不要求django-guardian包,并且应该支持其他对象级后端同样出色。

与DjangoModelPermissions您一样,您可以通过覆盖DjangoObjectPermissions和设置.perms_map属性来使用自定义模型权限。有关详细信息,请参阅源代码。

注意:如果你需要的对象级别view的权限GET,HEAD并OPTIONS请求,你要还考虑增加的DjangoObjectPermissionsFilter类,以确保该列表只端点返回结果包括用户拥有适当的查看权限的对象。
API参考

自定义权限

要实现自定义权限,请覆盖BasePermission并实现以下方法之一或两者:

  • .has_permission(self, request, view)
  • .has_object_permission(self, request, view, obj)

True如果应该授予请求访问权限,则应返回方法,False否则返回。

如果您需要测试请求是读取操作还是写入操作,则应该针对常量检查请求方法,该常量SAFE_METHODS是包含的元组'GET''OPTIONS''HEAD'

注意:has_object_permission只有在has_permission已经通过视图级别检查时才会调用实例级方法。另请注意,为了运行实例级检查,视图代码应显式调用.check_object_permissions(request, obj)。如果您使用的是通用视图,则默认情况下将为您处理。(基于函数的视图需要显式检查对象权限,否则会PermissionDenied导致失败。)

7、频率

Throttles类似于权限,因为它确定是否应该授权请求。Throttles表示临时状态,用于控制客户端可以对API发出的请求的速率。

与权限一样,可以使用多个限制。您的API可能对未经身份验证的请求具有限制性限制,并且对经过身份验证的请求限制较少。

您可能希望使用多个限制的另一种情况是,如果您需要对API的不同部分施加不同的约束,因为某些服务特别是资源密集型。

如果要同时施加突发限制速率和持续限制速率,也可以使用多个节流阀。例如,您可能希望将用户限制为每分钟最多60个请求,每天1000个请求。

Throttles不一定仅涉及限速请求。例如,存储服务可能还需要限制带宽,并且付费数据服务可能想要限制正在访问的特定数量的记录。

如何确定频率

权限和身份验证一样,REST框架中的限制始终定义为类列表。

在运行视图的主体之前,检查列表中的每个频率组件。如果任何频率组件检查失败,exceptions.Throttled将引发异常,并且视图的主体将不会运行。

自定义throtle组件

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])

自定义组件配置:

# 全局配置
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':[
        'app02.utils.throttle.UserRateThrottle',
    ],
}

# 视图类中的自定义配置
throttle_classes = [VisitThrottle,]

内置频率组件

class VisitThrottle(SimpleRateThrottle):

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

        return self.get_ident(request)

配置:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':[
        'app02.utils.throttle.UserRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        "visit_rate":"10/m"
    }
}

8、url分发

在前面写的rest-framework框架的代码可以看到,逻辑的代码方面都很简洁,因为在框架中已经将这些具体的功能都封装好了,不必让用户自己来编写这些重复的代码,但是,一看url还是会感觉非常复杂,要自己写的代码太多,还要自己传入需要的参数,如果url过多还是会造成代码的冗余。不过这个也不用担心,在这个框架中早已经将具体的解决方法都写好了。

具体用法:

from rest_framework import routers

# 调用routers模块中的DefaultRouter类生成一个对象
router=routers.DefaultRouter()

# 通过这个对象调用注册方法,将url的路径和具体的视图类当做参数传入其中
router.register("courses",views.CourseModelView)

# 然后直接使用include的进行分发
url("^",include(router.urls))    

该方法有两个必需参数register()

  • prefix - 用于此组路由的URL前缀。
  • viewset - 视图集类。

(可选)您还可以指定其他参数:

  • base_name - 用于创建的URL名称的基础。如果未设置,将根据queryset视图集的属性自动生成基本名称(如果有)。请注意,如果视图集不包含queryset属性,则必须base_name在注册视图集时进行设置。

生成的url模式

网址格式:^users/$ 名称:'user-list'
网址格式:^users/{pk}/$ 名称:'user-detail'
网址格式:^accounts/$ 名称:'account-list'
网址格式:^accounts/{pk}/$ 名称:'account-detail'

官网:Routers - Django REST framework

9、渲染器

 REST框架包含许多内置的Renderer类,允许您返回各种媒体类型的响应。还支持定义自己的自定义渲染器,这使您可以灵活地设计自己的媒体类型。

设置渲染器

可以使用该DEFAULT_RENDERER_CLASSES设置全局设置默认的渲染器集。例如,以下设置将JSON用作主要媒体类型,还包括自描述API。

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    )
}

还可以自定义单个视图类的响应器,在视图类中添加如下参数

renderer_classes = (JSONRenderer, )

官网:Renderers - Django REST framework

10、分页器

 在rest-framework框架内部也对自定义分页样式支持。分页主要是因为大量的数据无法同时展示在一个页面上这就需要用到分页了。

分页API可以支持:

  • 分页链接是作为响应内容的一部分提供的。
  • 响应标头中包含的分页链接,例如Content-RangeLink

设置分页样式

可以使用DEFAULT_PAGINATION_CLASSPAGE_SIZE设置键全局设置分页样式。例如,要使用内置限制/偏移分页,您可以执行以下操作:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 100
}

自定义分页样式

还可以使用pagination_class在单个视图上使用分页功能,但是这个需要自定义分页类

from rest_framework.pagination import PageNumberPagination

class MyPageNumberPagination(PageNumberPagination):
    page_size = 2
    page_size_query_param="size"
    max_page_size=4

在这个类中可以自定义自己想要的分页格式,定义完成后就可以在想要自定义分页的视图类中添加参数

pagination_class = MyPageNumberPagination()

或者使用DEFAULT_PAGINATION_CLASS设置全局应用样式。例如:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.MyPageNumberPagination'
}

官网:Pagination - Django REST framework

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值