Django让web开发更简单(六):整体使用rest_framework

rest_framework的使用

首先看看该框架的功能:
1、 解析器
2、 序列化组件
3、 APIView
4、 通用视图(mixin)
5、 分页组件
6、 响应器
7、 路由注册器
8、 认证组件
9、 权限组件
10、 限流

解析器

REST framework 包含许多内置的解析器类,允许接受各种媒体类型(media types)的请求。还支持自定义解析器,这使你可以灵活地设计 API 接受的媒体类型。

在settings文件中配置文件:

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

如上,可以使用 DEFAULT_PARSER_CLASSES 设置默认的全局解析器。如上,设置将带有JSON 、表单数据内容的请求,而不是默认的 JSON。详细解释请参照rest_framework文档。

除了默认设置外,还可以对单个视图或视图集设置,详细解释请参照rest_framework文档。

序列化组件

序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python 数据类型,然后可以将它们轻松地呈现为 JSON ,XML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。

因此,这些是有代码量的,rest_framework对这部分做了优化,引入了Serializers。在实际使用过程中,我们会在应用里,添加serializes.py文件,来引入序列化器。

在serializes.py添加:

from .models import Article, Reporter, testmysql
from rest_framework import serializers
from rest_framework import validators
from rest_framework.validators import UniqueValidator

class testmysqlSerializer(serializers.Serializer):

    student_name = serializers.CharField(max_length=16, validators=[validators.UniqueValidator(queryset=testmysql.objects.all(), message='数据已存在')])
    course_name = serializers.CharField(max_length=16)

APIView

REST framework 提供了一个 APIView 类,它继承于 Django 的 View 类。

APIView 类与不同的 View 类有所不同:
1、传递给处理方法的 request 对象是 REST framework 的 Request 实例,而不是Django 的 HttpRequest 实例。
2、处理方法可能返回 REST framework 的 Response ,而不是 Django 的 HttpResponse。该视图将管理内容协商,并在响应中设置正确的渲染器。
3、任何 APIException 异常都会被捕获并进行适当的响应。
传入的请求会进行认证,在请求分派给处理方法之前将进行适当的权限检查(允许或限制)。

像往常一样,使用 APIView 类与使用常规 View 类非常相似,传入的请求被分派到适当的处理方法,如 .get() 或 .post() 。此外,可以在类上设置许多属性(AOP)。

在views.py添加:

from django.shortcuts import render
from django.http import JsonResponse
import json
from firstapp.models import testmysql
from .serializers import ArticleSerializer, testmysqlSerializer
from rest_framework.views import APIView

# Create your views here.


class student(APIView):
    def post(self, request):
        response = {}  # 响应
        if request.method == "POST":
            req = json.loads(request.body)
            print(req)
        else:
            response["msg"] = "请求方法错误"
            response["code"] = 400
            return JsonResponse(response)

        a = testmysqlSerializer(data=req)
        if a.is_valid():
            testmysql.objects.create(**a.validated_data)
        else:
            return JsonResponse(a.errors)
        response["错误码"] = 200
        return JsonResponse(response)

在urls.py添加:

urlpatterns = [
    path('student/', student.as_view())
]

如上,是apiView的应用方式,代码不用运行,理解即可。

通用视图(mixin)

基于类的视图的一个主要优点是它们允许你编写可重复使用的行为。 REST framework 通过提供大通用视图,来提供常用模式。我们需要充分利用这一点。

REST framework 提供的通用视图允许您快速构建紧密映射到数据库模型的 API 视图。

如果通用视图不符合需求,可以使用常规的 APIView 类,或者利用 mixin 特性和基类组合出可重用的视图。

mixin可以大大简化代码量,当然,这种方式写出来的接口,灵活度就不高了。

1、mixin相关组件的使用

在urls.py添加:

urlpatterns = [
    path('test01/', test01_student.as_view()),
    path('test02/<int:pk>/', test02_student.as_view())
]

在views.py中添加:


class test01_student(ListModelMixin, CreateModelMixin, GenericAPIView):
    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

    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 test02_student(UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, GenericAPIView):
    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

    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)

如上,通过视图写出的接口相当简洁。

2、generics的使用

在views.py中添加:

from rest_framework import generics

class test03_student(generics.ListCreateAPIView):
    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

class test04_student(generics.RetrieveUpdateDestroyAPIView):
    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

如上,通过该组件,直接实现了1中的接口功能。

3、ModelViewSet使用

在urls.py中添加:

urlpatterns = [
    path('test05/', test05_student.as_view({"get":"list","post":"create"})),
    path('test05/<int:pk>/', test05_student.as_view({"get":"retrieve","delete":"destroy","put":"update"})),
]

在views.py中添加:

from rest_framework.viewsets import ModelViewSet

class test05_student(ModelViewSet):
    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

详细解释请参照rest_framework文档。

分页组件

REST framework 包含对可定制分页样式的支持。这使你可以将较大的结果集分成单独的数据页面。
分页 API 支持:
1、以分页链接的形式作为响应内容的一部分。
2、以分页链接的形式包含在响应的 header 中,如 Content-Range 或 Link .

内置的样式目前是以分页链接的形式作为响应内容的一部分。使用可浏览的 API 时,此样式更易于访问。

分页仅在你使用通用视图或视图集时自动执行。如果你使用的是常规 APIView ,则需要自己调用分页 API 以确保返回分页响应。示例请参阅 mixins.ListModelMixin 和generics.GenericAPIView 类的源代码。

可以通过将分页类设置为 None ,关闭分页。

1、PageNumberPagination
(1) APIView

class test07_student(APIView):
    class Pages(PageNumberPagination):
        page_size = 10

    pagination_class = Pages

    def get(self, request):
        class Pages(PageNumberPagination):
            page_query_param = "page" # 设置url参数page
            page_size_query_param = "size" # 设置url参数size
            page_size = 10 # 默认显示

        book_obj = testmysql.objects.all()
        P = Pages()
        paged_book_list = P.paginate_queryset(book_obj, request)
        T = testmysqlSerializer(paged_book_list, many=True)
        data = T.data  # 序列化接口
        return Response(data)

(2)ModelViewSet

class test06_student(ModelViewSet):
    class Pages(PageNumberPagination):
        page_size = 10

    pagination_class = Pages

    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

2、LimitOffsetPagination
(1)ModelViewSet

class test08_student(ModelViewSet):
    class Pages(LimitOffsetPagination):
        default_limit = 10  # 每页显示
        offset_query_param = 'offset'  # 当前所在的位置
        limit_query_param = 'limit'  # 往后取几条

    pagination_class = Pages

    queryset = testmysql.objects.all()
    serializer_class = testmysqlSerializer

更多分页组件,请查看rest_framework官方文档。

响应器

你不太可能希望为 REST framework 提供自定义内容协商方案,但如果需要,你可以这样做。要实现自定义内容协商方案,请覆盖 BaseContentNegotiation 。
REST framework 的内容协商类处理选择适当的请求解析器和适当的响应渲染器,因此你应该实现.select_parser(request, parsers) 和 .select_renderer(request, renderers,format_suffix) 方法。
select_parser() 方法应从可用解析器列表中返回一个解析器实例,如果没有任何解析器可以处理传入请求,则返回 None 。
select_renderer() 方法应该返回(渲染器实例,媒体类型)的二元组,或引发NotAcceptable 异常。

解析器parsers在Settings文件中配置,响应器renderer也在该文件配置:

REST_FRAMEWORK={
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
}

与解析器一样,响应器可以根据客户端的请求,来返回格式,如上面的JSON格式,当然,更多内容,请查看相关文档。

路由注册器

因为我们使用的是ViewSet类而不是View类,如ModelViewSet。所以我们实际上不需要自己设计URL conf。可以使用Router类自动处理将资源连接到视图和url中的约定。我们所需要做的就是向路由器注册适当的视图集,然后让它来完成剩下的工作。

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from firstapp.views import add_data, query_data, update_data, delete_data, student, \
    test01_student, test02_student, test03_student, test04_student, test05_student, \
    test06_student, test07_student, test08_student


# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'test09', test08_student)

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
    path('firstapp/', add_data),
    path('firstapp/<int:pk>/', query_data),
    path('firstapp/update/<int:pk>/', update_data),
    path('firstapp/delete/<int:pk>/', delete_data),
    path('student/', student.as_view()),
    path('test01/', test01_student.as_view()),
    path('test02/<int:pk>/', test02_student.as_view()),
    path('test03/', test03_student.as_view()),
    path('test04/', test04_student.as_view()),
    path('test05/', test05_student.as_view({"get":"list","post":"create"})),
    path('test05/<int:pk>/', test05_student.as_view({"get":"retrieve","delete":"destroy","put":"update"})),
    path('test06/', test06_student.as_view({"get": "list", "post": "create"})),
    path('test06/<int:pk>/', test06_student.as_view({"get": "retrieve", "delete": "destroy", "put": "update"})),
    path('test07/', test07_student.as_view()),
    path('test07/<int:pk>/', test07_student.as_view()),
    path('test08/', test08_student.as_view({"get": "list", "post": "create"})),
    path('test08/<int:pk>/', test08_student.as_view({"get": "retrieve", "delete": "destroy", "put": "update"})),
]

如上,通过DefaultRouter()可以自动生成路由,更多路由类,请查看官方文档。

认证组件

身份验证是将传入请求与一组识别凭证(例如请求的用户或其签名的令牌)相关联的机制。然后,权限
和限制策略可以使用这些凭据来确定请求是否应该被允许。

REST framework 提供了许多开箱即用的身份验证方案,同时也允许你实施自定义方案。

身份验证始终在视图的开始处运行,在执行权限和限制检查之前,在允许继续执行任何其他代码之前。
request.user 属性通常会设置为 contrib.auth 包的 User 类的一个实例。

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

注意: 不要忘记, 身份验证本身不会(允许或不允许)传入的请求,它只是标识请求的凭据。

默认的认证方案可以在settings.py文件中使用DEFAULT_AUTHENTICATION_CLASSES全局设置。例如:

REST_FRAMEWORK={
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ),
}

如上是3种认证方案:

BasicAuthentication:该认证方案使用 HTTP Basic Authentication,并根据用户的用户名和密码进行签名,通常只适用于测试,如果需要自定义认证,需要继承该类。

TokenAuthentication:此认证方案使用简单的基于令牌的 HTTP 认证方案。令牌身份验证适用于 client-server 架构,例如本机桌面和移动客户端。

SessionAuthentication:此认证方案使用 Django 的默认 session 后端进行认证。Session 身份验证适用于与您的网站在同一会话环境中运行的 AJAX 客户端。

确保在更改设置后运行 manage.py migrate ,这样才生效。rest_framework.authtoken 应用程序提供 Django 数据库迁移。

认证流程应该是前端进行登录,后端生成认证信息,后续的接口,都需要通过认证信息进行认证,这里采用自定义Token:

注册rest_framework.authtoken:

INSTALLED_APPS = [
    'rest_framework.authtoken',
]

自定义认证类:

class auth(BaseAuthentication):
   def authenticate(self, request):
       token = request.query_params.get("token")
       usertoken_obj = UserToken.objects.filter(token=token).first()
       if usertoken_obj:
           return usertoken_obj.user, usertoken_obj.token
       else:
           raise AuthenticationFailed("Token认证失败")

在认证的视图里添加自定义认证类:

class test10_student(APIView):
    authentication_classes = [auth, ]
    # permission_classes = [IsAuthenticated]

    class Pages(PageNumberPagination):
        page_size = 10

    pagination_class = Pages

    def get(self, request):
        class Pages(PageNumberPagination):
            page_query_param = "page" # 设置url参数page
            page_size_query_param = "size" # 设置url参数size
            page_size = 10 # 默认显示

        book_obj = testmysql.objects.all()
        P = Pages()
        # 分页
        paged_book_list = P.paginate_queryset(book_obj, request)
        T = testmysqlSerializer(paged_book_list, many=True)
        data = T.data  # 序列化接口
        return Response(data)

或者直接设置全局认证,需要在REST_FRAMEWORK注册自定义认证类。

执行迁移:

python manage.py makemigrations
python manage.py migrate

权限组件

与 authentication 和 throttling 一起,permission 决定是应该接受还是拒绝访问请求。

权限检查总是在视图的最开始处运行,在任何其他代码被允许进行之前。权限检查通常会使用request.user 和 request.auth 属性中的认证信息来确定是否允许传入请求。

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

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

稍微宽松的权限会允许通过身份验证的用户完全访问,而未通过身份验证的用户只能进行只读访问。这对应于 REST framework 中的 IsAuthenticatedOrReadOnly 类。

自定义的权限可以使用BasePermission,用法跟认证组件类似,可查阅官方文档。

限流

限流与权限类似,因为它确定是否应该授权请求。 限流阀指示临时状态,并用于控制客户端可以对API进行的请求速率。

与权限一样,可能会使用多种限流方式。你的 API 可能对未经身份验证的请求进行限流,对经过身份验证的请求限流较少。

如果你需要对 API 的不同部分使用不同的限流策略,由于某些服务特别占用资源,你可能想要使用同时有多种限流策略的另一种方案。

如果你想要同时实现爆发限流率和持续限流率,也可以使用多个限流阀。例如,你可能希望将用户限制为每分钟最多 60 个请求,并且每天最多 1000 个请求。

限流阀不一定只限制请求频率。例如,存储服务可能还需要对带宽进行限制,而付费数据服务可能希望对正在访问的某些记录进行限制。

使用方式可查阅官方文档,下面是一个例子:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion King

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值