Django REST Framework学习笔记

Django REST Framework学习笔记,这里不会对Django做介绍,只是自己对Django REST Framework学习的记录。

环境说明:

  • Python3.7

  • Django2.2

DRF是什么?为何要使用DRF?

WHAT:Django REST framework是一套基于Django框架编写RESTful风格API的组件(功能强大且灵活的工具包),用于构建Web API。

WHY:Django REST Framework可以在Django的基础上迅速实现API,并且自身还带有WEB的测试页面,可以方便的测试自己的API。

Django Rest Framework特点

  • 自动生成网站API文档;
  • 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
  • Authentication(身份认证):快速实现支持Auth1、Auth2方式的权限验证。
  • 提供了丰富的类视图、Mixin扩展类:简化视图的编写;
  • 内置了限流系统;
  • Request and Response(请求与响应):扩展了常规的HttpResquest和TemplateResponse;
  • ViewSet and Routers(视图集和路由):让路由设置更简便;

DRF安装

pip install djangorestframework
pip install markdown       # Markdown support for the browsable API.
pip install django-filter  # Filtering
pip install coreapi
pip install django-guardian

注意,DRF依赖Django,所以必须要安装Django(pip install django)。

DRF配置

(1)settings.py配置

要使用Django REST Framework(DRF), 我们首先需要在全局配置文件(setting.py)添加'rest_framework'INSTALLED_APPS中。

INSTALLED_APPS = (
    ...
    'rest_framework',
)

REST Framework API的任何全局设置都保存在一个名为REST_FRAMEWORK的配置字典中,我们可以在settings.py文件中进行设置,在后面我们再进行设置。

REST_FRAMEWORK = {
    ...
}

(2)urls.py配置

urls.py文件中配置API文档路由,此路由是后端API的文档地址。

from django.conf.urls import url, include
from rest_framework.documentation import include_docs_urls

urlpatterns = [
    ...
    path('docs/', include_docs_urls(title="中华诗歌")),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]

docs是DRF自动生成的文档的路由(title是文档标题),而api-auth是DRF登录的链接。

Serializers实践

Model定义

我们创建了一个名为poet的app,它定义两个极其简单的Model:Poet Model(诗人模型)与Poetry Model(诗歌模型)。

(1)诗人类

from django.db import models

class Poet(models.Model):
    name = models.CharField(max_length=30)
    dynasty = models.CharField(max_length=10, default="未知")
    introduction = models.TextField(blank=True)
    
    def __str__(self):
        return self.name

(2)诗歌类

class Poetry(models.Model):
    author = models.ForeignKey('Poet', on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    content = models.TextField()

    def __str__(self):
        return self.title

注意:别忘了Django的用法哦,定义完成模型之后别忘了注册app以及makemigrationsmigrate。当然,还有数据库配置,本文使用的是MySQL数据库,这里给出其配置:

#In settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '',
        'USER': '',
        'PASSWORD': '',
        'HOST': '127.0.0.1',
        'OPTIONS': { 'init_command': 'SET default_storage_engine=INNODB;' }#第三方登入需要
    }
}

定义View与Serializer

(1)APIView

APIView是DRF最基础的View,它继承的是Django的View(django.views.generic.View),它在Django View基础上增加了很多功能。

第1版View:APIView类实现Poet Model的列表功能。

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

from .model import Poet
from .serializers import PoetSerializer

class PoetListView(APIView):
    """诗人列表"""
    def get(self, request, format=None):
        poets = Poet.objects.all()
        poet_serializers = PoetSerializer(poets, many=True)
        return Response(poet_serializers.data)

注意:PoetSerializer(poets, many=True)代码中PoetSerializer的参数many=True代表传给它的参数poets是一个列表;如果是单个数据对象,可不配置many参数。

如上示例,和Django View很像,get方法也是处理GET请求;PoetSerializer是Poet模型对象的序列化类,我们只需要获取Poet的列表,然后将列表传给序列化类(PoetSerializer)得到序列化对象(poet_serializers),最后用Response返回poet_serializers.data。当然,也有post方法,下面给出示例:

from rest_framework import status
def post(self, request, format=None):
    """
    因为是诗人数据,用户一般不能创建,这里只给出一个小例子。
    serializer.save()方法会调用serializer类的create方法。
    即serializer.save()将调用PoetSerializer.create()方法。
    """
        serializer = PoetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

(2)serializers.Serializerserializer.ModelSerializer

这里讨论SerializerModelSerializer,并分别实现第一版View中的PoetSerializer。首先在poet app中创建python文件serializers.py。

  • Serializer的功能相当于Django的form功能,可以将数据序列化为json。

    #poet.serializers
    from rest_framework import serializers
    
    from .models import Poet
    
    class PoetSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        name = serializers.CharField(max_length=30, required=True)
        dynasty = serializers.CharField(max_length=10, default="未知")
    
        #def create(self, validated_data):
        #    return Poet.objects.create(**validated_data)
        
        #def update(self, instance, validated_data):
        #	...
    

    如上,使用Serializer实现序列化会让人感觉到累赘,因为我们的Model类就是这样定义的。

  • ModelSerializer继承于Serializer,相比其父类,ModelSerializer自动实现了以下三个步骤:

    1. 根据指定的Model自动检测并生成序列化的字段,不需要提前定义;
    2. 自动为序列化生成校验器;
    3. 自动实现了create()方法和update()方法。
    class PoetSerializer(serializers.ModelSerializer):
        class Meta:
            model = Poet
            fields = ('id', 'name', 'dynasty')
            #fields = "__all__"
    

    fields元组代表了需要做序列化/反序列化的字段,如果所以字段都需要序列化/反序列化,可以写成fields = "__all__"

写完View之后,配置如下URL:

from poet.views import PoetListView

urlpatterns = [
    ...
    path('poet/', PoetListView.as_view(), name='poet'),
]

启动系统查看页面信息Django REST Framework学习笔记_第1张图片

(3)GenericAPIViewmixins方法

mixins有如下几个Mixin类:

  • ListModelMixin:提供了list方法;

  • CreateModelMixin:提供了create方法;

  • RetrieveModelMixin:提供了retrieve方法;

    此方法可返回某条记录的详细信息。比如,/poet/返回诗人列表,那么/poet/{id}(/poet/1)则返回id为1的诗人的详细信息。

  • UpdateModelMixin:提供了update方法;

  • DestoryModelMixin:提供了destory方法。

GenericAPIView类继承自APIView,在APIView基础上增加了许多功能,如下属性列表:

  • queryset:需要返回的查询列表;
  • serializer_class :序列化类
  • lookup_field = ‘pk’:根据数据库表哪个字段来查找(默认是id,即pk);
  • filter_backends:过滤后端;
  • pagination_class:分页类(为queryset做分页)。

第二版View:使用mixins类组合GenericAPIView实现Poet Model的列表功能。

from rest_framework import generics
from rest_framework import mixins

class PoetListView(mixins.ListModelMixin,
                  generics.GenericAPIView):
    queryset = Poet.objects.all()#返回列表
    serializer_class = PoetSerializer#序列化类

    def get(self, request, *args, **kwargs):
        """此方法如果不定义,则405错误:Get Method Not Allow.
        list方法继承自ListModelMixin"""
        return self.list(request, *args, **kwargs)

list方法会帮我们做很多事情,比如分页、序列化等;上面代码指明了需要序列化的列表及序列化类,而背后的操作都是list帮我们完成。

在generics(rest_framework.generics)中,还有许多类,它们都是Mixin类和GenericAPIView的组合:

  • generics.ListAPIViewmixins.ListModelMixingenerics.GenericAPIView的组合,并提供了get方法;

    #第二版View的改写版
    class PoetListView(generics.ListAPIView):
        queryset = Poet.objects.all()
        serializer_class = PoetSerializer
    
  • CreateAPIViewmixins.CreateModelMixingenerics.GenericAPIView的组合,并提供了post方法;

  • ListCreateAPIViewmixins.CreateModelMixinmixins.ListModelMixingenerics.GenericAPIView的组合,并提供了get、post方法;

  • 等等。

分页设置

全局配置实现分页

前面说到REST Framework有个全局配置REST_FRAMEWORK,我们可以通过这个来配置分页:可以使用DEFAULT_PAGINATION_CLASS(分页类)和PAGE_SIZE(页面大小)设置分页样式,DEFAULT_PAGINATION_CLASSPAGE_SIZE默认为None,我们需要设置这两个参数。

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

实现分页类

全局配置将应用于所有的View,而有些类想单独设置分页如何?当然,我们可以自定义分页类。

第三版View:设置分页类的View来显示Poet Model 列表。

from rest_framework.pagination import PageNumberPagination

class PoetPagination(PageNumberPagination):
    """Poet 分页类"""
    page_size = 1
    page_size_query_param = "page_size"
    page_query_param = "p"#?p=1,默认为page
    max_page_size = 20
    
class PoetListView(generics.ListAPIView):
    queryset = Poet.objects.all()
    serializer_class = PoetSerializer
    pagination_class = PoetPagination

Django REST Framework学习笔记_第2张图片

注意:

  1. 因为我只用了两条诗人数据,为了显示分页效果,所以这里我将page_size设置为1;
  2. 因为模型设置的非常简单,Poet类并没有ImageField字段;但这并不影响我们,如果有一个类有ImageField字段并把它加入了Serialier字段中,那么,DRF会自动将图片完整路径返回。比如,数据库存储的default.png,那么DRF返回的数据将是127.0.0.1/meida/uploads/poet/default.png

viewsetsRouters

viewsetsrouters是配套使用的。

viewsets.GenericViewSet

GenericViewSet继承了ViewSetMixinGenericAPIView,相当于GenericAPIView增加了ViewSetMixin的功能。

ViewSetMixin重写了as_view方法,可以让注册URL变得更简单(与router搭配);它还提供了许多方法,如initialize_request,它在view的基础上设置了很多action(一些请求所代表的动作),initialize_request可以让我们实现动态serializer_class。

viewsetsrouters的使用

先给出Poetry的Serializer:

#poet.serializer
class PoetrySerializer(serializers.ModelSerializer):
    #实例化外键序列化类,将返回外键信息(如果不设置,则返回外键的主键字段)
    author = PoetSerializer()
    class Meta:
        model = Poetry
        fields = "__all__"

第四版View:viewsets与routers实现Poetry Model List。

#poet.views
from rest_framework import mixins
from rest_framework import viewsets

class PoetryListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """这个类可不用定义get,post等方法,只需在urls文件设置绑定即可
    """
    queryset = Poetry.objects.all()
    serializer_class = PoetrySerializer

在urls.py中设置路由:

方式一:as_view方法绑定

from poet.views import PoetryListViewSet
#设置绑定,get方法将绑定到list方法
poetry_list = PoetryListViewSet.as_view({
        'get': 'list',
    })

urlpatterns = [
    ...
    path('shige/', poetry_list, name='poetry'),
]

Django REST Framework学习笔记_第3张图片

方式二:使用router设置路由,此方式将取代方式一。

from rest_framework.routers import DefaultRouter
from poet.views import PoetryListViewSet

router = DefaultRouter()#实例化一个router

router.register(r'shige', PoetryListViewSet, base_name="poetry")#设置路由

urlpatterns = [
    ...
    path('', include(router.urls)),#将这个加入url
]

注意:viewsets和router使得编写API、设置路由变得异常简单;router会自动将get方法转到list方法,post方法转到create方法…

一般来说,DRF定义View都所使用Mixin类和GenericViewSet进行组合。如下,获取Poetry详情只需要在第四版View加一行代码(继承mixins.RetrieveModelMixin);前面说到过,RetrieveModelMixin提供了retrieve方法,可以显示单条记录的详情。

class PoetryViewSet(mixins.ListModelMixin,
					mixins.RetrieveModelMixin,#加此行
					generics.GenericViewSet):
    ...

如图Django REST Framework学习笔记_第4张图片

RequestResponse

Request

REST框架的Request类扩展了标准HttpRequest,增加了对REST框架灵活的请求解析和请求认证的支持。

request.data返回请求正文的已解析内容,类似于标准request.POSTrequest.FILES属性;当然,它还有其它的功能:

  • 它包括所有已解析的内容,包括文件和非文件输入。
  • 它支持解析除HTTP方法之外的其他内容POST,这意味着您可以访问内容PUTPATCH请求。
  • 它支持REST框架的灵活请求解析,而不仅仅支持表单数据。例如,您可以像处理传入表单数据一样处理传入的JSON数据。

具体请参考官方文档Requests。

Response

签名: Response(data, status=None, template_name=None, headers=None, content_type=None)

Response使用的渲染器本身不能处理复杂的数据类型,例如Django模型实例,因此您需要在创建Response对象之前将数据序列化为原始数据类型:可以使用REST框架的Serializer类来执行此数据序列化,或使用自己的自定义序列化。

参数:

  • data:响应的序列化数据。
  • status:响应的状态代码。默认为200.另请参见状态代码。
  • template_nameHTMLRenderer选择时使用的模板名称。
  • headers:要在响应中使用的HTTP标头的字典。
  • content_type:响应的内容类型。通常,这将由内容协商确定的渲染器自动设置,但在某些情况下可能需要明确指定内容类型。

具体参考官方文档Responses。

DRF的过滤、搜索与排序

首先,我们要清楚,在View中,queryset是需要序列化的模型数据列表,而get_queryset方法做的事也是如此(get_queryset返回queryset),我们可以使用get_queryset方法来代替queryset属性。

	def get_query(self):
 		"""
 		queryset=Poetry.objects.filter(author__name="杜甫")
 		"""
        return Poetry.objects.filter(author__name="杜甫")

过滤

使用django-filter(可以在github上搜索django-filter)来设置过滤(前面我们已经安装过了pip install django-filter)。将django-filter设置到INSTALLED_APPS中:

INSTALLED_APPS = [
    ...
    'django_filters',#支持REST框架的高度可定制的字段过滤
]

使用:

from django_filters.rest_framework import DjangoFilterBackend

class PoetryListViewSet(mixins.ListModelMixin,
                        viewsets.GenericViewSet,
                        mixins.RetrieveModelMixin):
    queryset = Poetry.objects.all()
    serializer_class = PoetrySerializer
    filter_backends = (DjangoFilterBackend,)#设置后端
    filter_fields = ("author",)#设置过滤字段

如图Django REST Framework学习笔记_第5张图片

当然也可以自定义Filter类来实现过滤。我们新建一个filters.py(poet.filter)文件:

from django_filters import rest_framework as filters

from poet.models import Poetry

class PoetryFilter(filters.FilterSet):
    #等价于Poetry.objects.filter(title__contains=)
    title = filters.CharFilter(field_name="title", lookup_expr='contains')
    #定义函数,来实现过滤逻辑,method参数是函数名
    content = filters.CharFilter(method='content_filter')

    def content_filter(self, queryset, name, value):
        return queryset.filter(content__contains=value)

    class Meta:
        model = Poetry
        fields = ['author', 'title', 'content']#需要过滤的字段
from .filters import PoetryFilter

class PoetryListViewSet(mixins.ListModelMixin,
                        viewsets.GenericViewSet,
                        mixins.RetrieveModelMixin):
    queryset = Poetry.objects.all()
    serializer_class = PoetrySerializer
    filter_backends = (DjangoFilterBackend,)
    filter_class = PoetryFilter

参考文档Django-filter。

过滤、搜索与排序的组合使用

搜索和排序就不单独介绍,直接用代码演示。

第五版View:实现Poetry Model List的过滤、搜索和排序。使用过滤要将DjangoFilterBackend添加到filter_backends中,而使用搜索和排序则需要将filters.SearchFilterfilters.OrderingFilter加进去;search_fields表示需要进行搜索的字段,而ordering_fields是排序的字段。

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters

class PoetryListViewSet(mixins.ListModelMixin,
                        viewsets.GenericViewSet,
                        mixins.RetrieveModelMixin):
    queryset = Poetry.objects.all()
    serializer_class = PoetrySerializer
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    filter_class = PoetryFilter
    search_fields = ('=title', 'content')#title字段精确搜索
    ordering_fields = ('id',)

如图Django REST Framework学习笔记_第6张图片

注意:

  • 过滤会进行精确匹配,而搜索则是模糊匹配。
  • 搜索行为可以通过在其中添加各种字符来限制search_fields
    1. '^'开始 - 搜索。
    2. '='完全匹配。
    3. '@'全文搜索。(目前只支持Django的MySQL后端。)
    4. '$'正则表达式搜索。
  • 参考文档Filters。

跨域访问

前后端分离系统中,前端系统去访问后端API,基本每一个请求都是跨域访问的。而DJango是拒绝跨域访问的,如果不进行设置那么前端系统将会被后端拒绝访问。当然,前端也有解决跨域的方法,但这里主要讲的是后端,所以这里会介绍后端如何解决跨域问题。

  1. 安装django-cors-headers
pip install django-cors-headers
  1. 将corsheaders注册到INSTALLED_APPS中
INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]
  1. 'corsheaders.middleware.CorsMiddleware'加入到setting文件中的MIDDLEWARE中;注意,必须要放在在'django.middleware.common.CommonMiddleware'之前,不然可能会出错。
MIDDLEWARE = [  # Or MIDDLEWARE_CLASSES on Django < 1.10
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]
  1. 设置CORS_ORIGIN_ALLOW_ALL or CORS_ORIGIN_WHITELIST
CORS_ORIGIN_ALLOW_ALL = True#接受所有来源

或者

# 白名单设置
CORS_ORIGIN_WHITELIST  = [
    "www.example.com",
    "127.0.0.1:8080",
]

更详细的配置请参考django-cors-headers。

JWT用户认证

一般前后端分离系统做身份验证都是使用Token验证,但TokenAuthentication有两个缺点

  1. 分布式系统涉及同步问题。
  2. Token值无过期时间(数据表只有key,create_time,user_id),存在不安全隐患(泄露)。

并且,设置全局Token认证是有副作用的:我们知道,Token信息有误时,是会抛异常的(返回40X),那用户如果访问公开数据时,Token信息有误(错误或失效),返回的40x页面是很不友好的。所以,可以在View类单独设置身份认证。

前后端分离系统常用认证方式是Json Web Token。

Json Web Token认证

这里介绍使用Json Web Token认证来实现用户登录(参考django-rest-framework-simplejwt)。

  1. 安装
pip install djangorestframework_simplejwt
  1. 配置DEFAULT_AUTHENTICATION_CLASSES(In settings.py)
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',#Json Web TokenAuthentication
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),

注意:不建议将JWT验证放在全局配置中,这意味着不管是公开信息还是需要认证的信息,请求时都需要带上token值;在某种情况下,这会引起公开页面也无法访问(token失效时,会返回40X),所以最好将JWT验证放在相应的View中。在设置权限认证与用户认证将会介绍。

Q:JWT认证,客户端如何退出?

A:JWT认证模式并不会把token信息保存在服务器端,而是保存在客服端浏览器,
所以,退出只需要在浏览器删除cookies信息即可。

  1. 配置路由(In urls.py)
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    url(r'^login/$', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    url(r'^login/refresh/$', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

使用Postman软件来测试Django REST Framework学习笔记_第7张图片

自定义登录验证

说到认证,我这里讲一下如何更改Django默认认证模式,我们可以通过自定义认证类来完成自定义登录。代码如下:

class CustomBackend(ModelBackend):
    """
    自定义用户验证
   		可以使用邮箱进行登录。
    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(username=username)|Q(email=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None

定义好用户验证类之后,将其配置到settings中:

AUTHENTICATION_BACKENDS = (
    #自定义用户认证类
    'user.views.CustomBackend',#路径
)

设置权限认证与用户认证

用户信息修改

信息修改需要验证用户身份,我们通过这个简单了解DRF权限认证方式。

定义UserPersonalCenterSerializer:User使用的是Django默认的User Model。UniqueValidator会进行唯一性校验。

#user.serializer
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.validators import UniqueValidator

User = get_user_model()

class UserPersonalCenterSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(label="邮箱", validators=[UniqueValidator(queryset=User.objects.all())])
    class Meta:
        model = User
        fields = ("email",)

permission_classes是权限认证类,指访问此接口应具备的权限。authentication_classes是登录验证方式类。

#user.views
from django.contrib.auth import get_user_model
from rest_framework import permissions
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.authentication import SessionAuthentication
from .serializers import UserPersonalCenterSerializer

User = get_user_model()

class UserPersonalCenterViewSet(mixins.UpdateModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """用户个人中心
    实现更新操作,只需继承UpdateModelMixin即可。
    """
    queryset = User.objects.all()
    serializer_class = UserPersonalCenterSerializer
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = (JWTAuthentication, SessionAuthentication)

    def get_object(self):
        """retrieve和delete方法会用到此方法,此方法应返回当前用户
            所以,不管访问127.0.0.1/user/id中id为多少,都是返回当前用户的信息
        """
        return self.request.user

如图,登录状态下,PUT email,将修改email信息,且email信息会进行唯一性检验。Django REST Framework学习笔记_第8张图片

动态获取serializer

动态获取序列化磊只需要在View中定义get_serializer_class方法,且一定要返回一个Serializer类(所以最后一行的代码十分重要,如果不写的话很可能会抛异常)。

    def get_serializer_class(self):
        """
        动态访问序列化类:self.active记录的是相应动作的名称。
        """
        if self.action == 'retrieve':
            return UserPersonalCenterSerializer
        elif self.action == 'create':
            return UserRegisterViewset
        return UserPersonalCenterSerializer

动态设置permission

动态获取序列化磊只需要在View中定义get_permissions方法。

    def get_permissions(self):
        """
        自定义权限访问,动态控制各函数权限
        	retrieve:用户信息详情,需要登录权限
        	create:注册,无须权限。
        """
        if self.action == 'retrieve':
            return [permissions.IsAuthenticated()]
        elif self.action == 'create':
            return []
        return []

自定义权限认证

自定义权限认证可以继承permissions.BasePermission,并定义其has_object_permission方法,此方法应该返回BOOL值(代表权限认证是否通过)。如下,定义一个IsOwnerOrReadOnly类,认证是否某条数据是否属于该用户或者该用户是否可以查看。

from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        # obj是数据库取出来的model对象
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `owner`.
        return obj.user == request.user

DRF缓存

为加快网站响应速度,我们一般会将一些数据放入到缓存中;本小节将介绍DRF如何设置缓存。

  1. 安装drf-extensions
pip install drf-extensions
  1. 使用:一般来说,Cache一般用在(GET方法)不经常变动的、公开的数据上,比如获取诗人列表,而私有数据一般不使用缓存(PUT、UPDATE等方法一般也不使用缓存)。使用drf-extensions的缓存非常简单,只需要在View中继承CacheResponseMixin(最好放在第一个继承位)。
from rest_framework_extensions.cache.mixins import CacheResponseMixin

class PoetListView(CacheResponseMixin,
                   generics.ListAPIView):
    queryset = Poet.objects.all()
    serializer_class = PoetSerializer

注意:

​ a. CacheResponseMixin缓存默认使用的是Local Memory Cache,如果系统重启,缓存将全部失效;

​ b. 设置Cache后还应该设置过期时间,如果设置为None(默认),意味着缓存不失效,除非重启服务。

  1. 全局配置:In settings.py

在settings中,drf-extensions的全局配置名为REST_FRAMEWORK_EXTENSIONS。

REST_FRAMEWORK_EXTENSIONS = {
    'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 15 #单位 s
}

如需redis缓存,可github搜索django-redis,查看其文档使用。

IP速率限制

IP限速可以防止爬虫影响系统稳定性,建议对某些关键的数据、对某些性能要求高的数据进行IP限速。本节讲解DRF(DRF自带有限速功能,不需要其他工具)进行IP限速的配置。

设置限制策略

可以使用DEFAULT_THROTTLE_CLASSESDEFAULT_THROTTLE_RATES设置全局设置默认限制策略。DEFAULT_THROTTLE_CLASSES是限速类,而DEFAULT_THROTTLE_RATES是限速规则。

如下'rest_framework.throttling.AnonRateThrottle'是针对未登录用户的限速类,'rest_framework.throttling.UserRateThrottle'是针对登录用户的限速类。同理'anon',user也是针对未登录和登录用户的限速规则。

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '30/minute',
        'user': '60/minute'
    }
}

注意:

  1. DEFAULT_THROTTLE_RATES速率的描述包括secondminutehourday
  2. REST_FRAMEWORK中设置IP限速为全局设置,将应用到所有页面(不包括后台管理)。

在View中设置IP限速

  • AnonRateThrottle

    rest_framework.throttling.AnonRateThrottle
    

    在View中设置throttle_classes = (AnonRateThrottle,)将会限制未登录用户的访问速率;如果你想限制来自未知来源的请求率,可以设置此类。

  • UserRateThrottle

    UserRateThrottle将限制用户在API中的给定请求率。

    rest_framework.throttling.UserRateThrottle
    

详细说明请参考文档Throttle。

示例:给Poetry List设置限速。

from rest_framework.throttling import UserRateThrottle
from rest_framework.throttling import AnonRateThrottle
from rest_framework import mixins
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters

from poet.model import Poetry
from poet.serializer import PoetrySerializer

class PoetryListViewSet(mixins.ListModelMixin,
                        viewsets.GenericViewSet,
                        mixins.RetrieveModelMixin):
    queryset = Poetry.objects.all()
    throttle_classes = (AnonRateThrottle, UserRateThrottle)
    serializer_class = PoetrySerializer
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    filter_class = PoetryFilter
    search_fields = ('=title', 'content')#title字段精确搜索
    ordering_fields = ('id',)

第三方登录

  1. 安装环境
pip install social-auth-app-django
  1. 配置到INSTALLED_APPS中(In setting.py)
INSTALLED_APPS = (
    ...
    'social_django',
    ...
)
  1. migrate:不需要makemigrations
./manage.py migrate
  1. 设置认证类AUTHENTICATION_BACKENDS(In setting.py)
AUTHENTICATION_BACKENDS = (
    #第三方登录配置格式:social_core.backends.open_id.OpenIdAuth'
    #open_id为social_core中的模块名称(也是社交软件名称),OpenIdAuth为文件中的认证类
    'social_core.backends.weibo.WeiboOAuth2',#微博
    'social_core.backends.qq.QQOAuth2',#qq
    'social_core.backends.weixin.WeixinOAuth2',#微信
    'django.contrib.auth.backends.ModelBackend',
)
  1. 配置url(In urls.py)
urlpatterns = [
    ...
    url('', include('social_django.urls', namespace='social')),
    ...
]
  1. 将以下两个上下文处理器加到TEMPLATES中(In setting.py)
TEMPLATES = [
    {
        ...
        'OPTIONS': {
            ...
            'context_processors': [
                ...
                'social_django.context_processors.backends',
                'social_django.context_processors.login_redirect',
                ...
            ]
        }
    }
]

使用了这个之后,第三方账号登录时它会帮我们创建一个用户,然后将第三方账号绑定到该用户;如果第三方账号登录时已经有登录用户,那么它不再帮我们创建用户,而是直接将第三方账号绑定到该用户。如下图数据表:Django REST Framework学习笔记_第9张图片

  1. 配置Key和Secret Key(In setting.py)

KEY和Secret Key格式为:

  • SOCIAL_AUTH_{社交软件名}_KEY

  • SOCIAL _AUTH_{社交软件名}_SECRET

    如下示例配置。

    #微博
    SOCIAL_AUTH_WEIBO_KEY = ''
    SOCIAL_AUTH_WEIBO_SECRET = ''
    #qq
    SOCIAL_AUTH_QQ_KEY = ''
    SOCIAL_AUTH_QQ_SECRET = ''
    #微信
    SOCIAL_AUTH_WEIXIN_KEY = ''
    SOCIAL_AUTH_WEIXIN_SECRET = ''
    

注意:KEY和SECRT Key需要自己去相应开放平台申请。

  1. 最后一步:配置第三方登录成功后的跳转页面(In setting.py)
#第三方登录成功跳转页面
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'

访问/login/{社交软件名}/即可跳转到第三方登录。Django REST Framework学习笔记_第10张图片

DOCS

Django REST Framework为网站API自动生成了直观的文档,在一开始我们也配置了其路由(/docs/),如下图Django REST Framework学习笔记_第11张图片

我们可在DOCS中测试API,当然,也可在相应的API接口调试。

你可能感兴趣的:(Django,Django,REST,Framework)