Django(16):rest_framework框架使用指南

news2024/11/19 4:37:06

目录

  • 1.安装配置
  • 2.数据序列化
    • 2.1 Serializer
    • 2.2 ModelSerializer
    • 2.3 序列化对象的属性和方法
  • 3.请求和响应
    • 3.1 Request
    • 3.2 Response
    • 3.3 状态码
    • 3.4 as_view
    • 3.5 format_suffix_patterns
    • 3.6 示例
  • 4.CBV构建(基于类的视图)
    • 4.1 如何构建
    • 4.2 类型视图的扩展功能
    • 4.3 类型视图的功能封装
  • 5.身份认证和权限管理
    • 5.1 权限限制
    • 5.2 身份认证API
    • 5.3 自定义认证权限
  • 6.接口文档
  • 7.视图集及路由配置

当需要和其他系统直接进行数据交互或前后端分类项目时,就需要接口来支持。

Django rest_framework是第三方框架,为在Django项目中实现Restful风格的数据接口提供非常友好支持。

1.安装配置

1.安装

 pip install djangorestframework

2.创建项目

创建子项目:

# 创建项目tutorial
django-admin startproject tutorial
# 创建knowledge子项目
cd tutorial/
django-admin startapp knowledge

添加路由,编辑主项目路由模块tutorial/tutorial/urls.py,如下:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('knowledge/', include('knowledge.urls'))
]

在配置中INSTALLED_APPS添加如下:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'quickstart'
]

编辑子项目的models.py,代码如下:

from django.db import models
from uuid import uuid4


class KnowledgeItem(models.Model):
    """知识项数据模型"""
    id = models.UUIDField(verbose_name="编号", primary_key=True, default=uuid4)   # 知识编号
    title = models.CharField(verbose_name="标题", max_length=100)                 # 标题
    content = models.TextField(verbose_name="内容")                               # 知识内容
    publish_time = models.DateTimeField(verbose_name="发布时间",auto_now_add=True) # 知识发布时间
    last_update_time = models.DateTimeField(verbose_name="修改时间", auto_now=True)# 知识修改时间
    remark = models.TextField(verbose_name="备注", null=True, blank=True)         # 知识备注条目

因此项目用于开发接口,不需要处理网页视图,所以不再创建网页文件结构。

后面的案例以此项目为例说明。

3.分页配置

Django rest_framework还提供了自己的分页配置方式,编辑配置文件,增加配置如下:

# 分页配置
REST_FRAMEWORK = {
    # 默认的数据分页处理模块
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # 每页展示数据量
    'PAGE_SIZE': 10
}

2.数据序列化

参考:https://blog.csdn.net/weixin_30369087/article/details/96688821

数据序列化是数据接口开发的核心,定义序列化模型一般有两种方式,一是使用serializers.Serializer,二是使用serializers.ModelSerializer。

2.1 Serializer

这种序列化的操作方式是Django rest_framework框架提供的底层序列化方式,可以对指定的数据模型对象进行数据序列化转换。

在子项目中,创建序列化模块serializers.py,定义序列化组件如下:

from rest_framework import serializers

from .models import KnowledgeItem


class KnowledgeSerializer(serializers.Serializer):
    """知识项序列化类型"""
    id = serializers.UUIDField(read_only=True)  # 编号
    title = serializers.CharField(required=True, max_length=100) # 标题
    content = serializers.CharField(required=True) # 内容
    remark = serializers.CharField(required=False, allow_blank=True, allow_null=True)# 备注

    def create(self, validated_data):
        """使用封装后的验证方法返回知识项对象"""
        return KnowledgeItem.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """使用数据更新已有对象属性的方法"""
        instance.title = validated_data.get("title", instance.title)
        instance.content = validated_data.get("content", instance.content)
        instance.remark = validated_data.get("remark", instance.remark)

这个序列化类中有两部分:

1.定义了要进行序列化的字段;这些字段负责将Python类型转换成JSON类型,即序列化的过程;

2.定义了当serializer.save()时用于生成Model对象的create()和update()方法,这两方法负责将JSON类型的数据转换成Python类型的数据,即反序列化的过程。

缺点:用Serializer还需要使用serializers.fields模块里的类型去自定义序列化字段,与model里代码重复。具体Serializer中的Field有哪些字段,可以参考源码,与Django中模型字段类似。

2.2 ModelSerializer

使用ModelSerializer继承了Serializer,在Serializer基础上封装了很多操作。最大好处是可根据指定的model自动检测并生成序列化的字段,不需要再定义,默认情况下,将所有Model类中的字段映射到ModelSerializer类中相应的字段。

修改上面的代码如下:

class KnowledgeSerializer(ModelSerializer):
    """知识项序列化类型"""
    class Meta:
        # 关联数据模型
        model = KnowledgeItem
        # 关联操作字段
        fields = ('id', 'title', 'content', 'remark')

2.3 序列化对象的属性和方法

Serializer序列化对象有以下属性和方法:

*1.save()*

在调用serializer.save()时,会创建或者更新一个Model实例(调用create()update()创建),具体根据序列化类的实现而定,如:

# .save() will create a new instance.
serializer = StudentSerializer(data=data)

# .save() will update the existing `comment` instance.
serializer = StudentSerializer(comment, data=data)

*2.create()、update()*

Serializer中的create()和update()方法用于创建生成一个Model实例,在使用Serializer时,如果要保存反序列化后的实例到数据库,则必须要实现这两方法之一,生成的实例则作为save()返回值返回。方法属性validated_data表示校验的传入数据。

*3. is_valid()*

当反序列化时,在调用Serializer.save()之前必须要使用is_valid()方法进行校验,如果校验成功返回True,失败则返回False,同时会将错误信息保存到serializer.errors属性中。

*4.data*

serializer.data中保存了序列化后的数据。

*5.errors*

当serializer.is_valid()进行校验后,如果校验失败,则将错误信息保存到serializer.errors属性中。

3.请求和响应

Django rest_framework对请求对象(Request)和响应对象(Response)进行了再次封装,扩展了功能。

3.1 Request

Django rest_framework的Request对象提供以下两个方法获取参数:

  • request.POST:获取POST请求的参数;
  • request.data:获取其他请求方式的参数;
  • request.query_params:相当于request.GET。

3.2 Response

这个对象可以根据客户端发送的请求头中规范的请求格式,对响应数据进行格式化转换和渲染

return Response(data)

3.3 状态码

REST framework为每个状态码提供了更加明确的标识,全部内容封装在rest_framework.status模块中。这样我们可以直接使用返回相应的状态码。代码如下:

"""
Descriptive HTTP status codes, for code readability.

See RFC 2616 - https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
And RFC 6585 - https://tools.ietf.org/html/rfc6585
And RFC 4918 - https://tools.ietf.org/html/rfc4918
"""


def is_informational(code):
    return 100 <= code <= 199


def is_success(code):
    return 200 <= code <= 299


def is_redirect(code):
    return 300 <= code <= 399


def is_client_error(code):
    return 400 <= code <= 499


def is_server_error(code):
    return 500 <= code <= 599


HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_102_PROCESSING = 102
HTTP_103_EARLY_HINTS = 103
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_421_MISDIRECTED_REQUEST = 421
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_425_TOO_EARLY = 425
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511

3.4 as_view

@as_view装饰器可以用于装饰视图函数,在Django框架提供的用户请求类型的基础,对客户端请求进行封装得到Request对象进行巨头业务处理,在处理完成后,可以通过Response对象对响应数据进行转换和渲染。

3.5 format_suffix_patterns

format_suffix_patterns用于添加请求格式标识符。代码如下:

urlpatterns = [
    # 增删改查知识项对象数据
    path("<uuid:pk>/", views.knowledge_detail),
    # 查询知识项列表数据
    path("", views.knowledge_list),
]

urlpatterns = format_suffix_patterns(urlpatterns)

添加之前,数据访问方式是http://127.0.0.1:8000/knowledge(访问指定的url地址),Accept: application/josn(限制接受JSON格式的数据)。

添加之后,可以通过在访问路由后添加后缀名称,直接访问数据的格式,并从接口获取数据,比如http://127.0.0.1:8000/knowledge/.json,表示直接从接口提取JSON格式数据。

3.6 示例

#######################################################################
# 基于函数的视图处理组件
#######################################################################
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view

from .models import KnowledgeItem
from .serializers import KnowledgeSerializer


@csrf_exempt
@api_view(['GET', 'POST'])
def knowledge_list(request, format=None):
    """知识项列表视图处理函数"""
    if request.method == "GET":
        # 查询所有的知识项数据
        knowledges = KnowledgeItem.objects.all()
        # 序列化对象数据
        serializers = KnowledgeSerializer(knowledges, many=True)
        # 返回查询到的知识项序列数据列表
        return JsonResponse(serializers.data, safe=False)

    elif request.method == "POST":
        # 获取知识项新数据
        # data = JSONParser().parse(request)
        # 反序列化数据
        serializers = KnowledgeSerializer(data=request.data)
        # 验证
        if serializers.is_valid():
            # 存储数据
            serializers.save()
            # 返回操作的数据
            return Response(serializers.data, status=status.HTTP_201_CREATED)
        return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)


@csrf_exempt
@api_view(['GET', 'PUT', 'DELETE'])
def knowledge_detail(request, pk, format=None):
    """知识项操作视图处理函数"""
    # 查询获取对应的知识项对象
    knowledge = get_object_or_404(KnowledgeItem, pk=pk)

    # 判断不同请求方式下的数据处理
    if request.method == "GET":
        """查询获取知识项对象"""
        serializer = KnowledgeSerializer(knowledge)
        return Response(serializer.data)
    elif request.method == "PUT":
        """更新知识项对象"""
        # 根据请求提交的数据反序列化数据
        serializer = KnowledgeSerializer(knowledge, data=request.data)
        # 验证并存储数据
        if serializer.is_valid():
            # 存储数据
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    elif request.method == "DELETE":
        # 删除对象数据
        knowledge.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

4.CBV构建(基于类的视图)

和Django框架一样, Django rest_framework也提供了视图处理函数和基于类型的视图组件,也就是CBV(Class Base View)。

4.1 如何构建

Django rest_framework通过APIView类实现了基于类型的视图组件构建,只要继承此类即可使用,定义方法时,通过方法名来区分请求方式。

还是以上面的子项目knowledge为例,重构view.py模块如下:

from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import KnowledgeItem
from .serializers import KnowledgeSerializer


class KnowledgeView(APIView):
    """知识项视图组件"""

    def get(self, request, format=None):
        """GET请求方式处理函数"""
        # 查询获取所有知识项对象
        knowledges = KnowledgeItem.objects.all()
        # 序列化数据
        serializers = KnowledgeSerializer(knowledges, many=True)
        # 返回响应数据
        return Response(serializers.data)

    def post(self, request, format=None):
        """新增知识项数据"""
        # 接受请求中包含的数据,并序列化数据
        serializer = KnowledgeSerializer(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)


class KnowledgeDetailView(APIView):
    """知识项详情视图组件"""
    def get_object(self, pk):
        """获取知识项对象的函数"""
        return get_object_or_404(KnowledgeItem, pk=pk)

    def get(self, request, pk, format=None):
        """GET请求方式视图处理方法"""
        serializer = KnowledgeSerializer(self.get_object(pk))
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        """PUT请求方式视图处理方法"""
        serializer = KnowledgeSerializer(self.get_object(pk), 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)

    def delete(self, request, pk, format=None):
        """DELETE请求方式视图处理方法"""
        knowledge = self.get_object(pk)
        knowledge.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

构建完视图后,添加路由的方式也相应改变:

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns

from . import views

app_name = 'knowledge'

urlpatterns = [
    # 增删改查知识项对象数据
    path("<uuid:pk>/", views.KnowledgeDetailView.as_view()),
    # 查询知识项列表数据
    path("", views.KnowledgeView.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

路由中的映射关系,通过APIView中的as_view方法进行绑定。

4.2 类型视图的扩展功能

为了提高项目开发效率,Django rest_framework框架对项目中常见的操作功能进行了封装,并提供了mixin组件。常用组件如下:

  • CreateModelMixin:提供了一个快速创建一个model实例的方法create();
  • ListModelMixin:提供了一个快速获取列表数据的方法list();
  • RetrieveModelMixin:提供了一个快速获取单个实例数据的方法retrieve();
  • UpdateModelMixin:提供了一个快速更新单个实例数据的方法update();
  • DestroyModelMixin:提供了一个快速删除单个实例数据的方法destroy();

源码如下:

"""
Basic building blocks for generic class based views.

We don't bind behaviour to http method handlers yet,
which allows mixin classes to be composed in interesting ways.
"""
from rest_framework import status
from rest_framework.response import Response
from rest_framework.settings import api_settings


class CreateModelMixin:
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}


class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class UpdateModelMixin:
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)


class DestroyModelMixin:
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

示例:

重构knowledge子项目的视图views.py,代码如下:

from rest_framework import mixins, status, generics
from rest_framework.response import Response

from .models import KnowledgeItem
from .serializers import KnowledgeSerializer


class KnowledgeView(generics.GenericAPIView,    # 视图组件
                    mixins.CreateModelMixin,    # 对象创建组件
                    mixins.ListModelMixin,):    # 对象类表查看组件
    """知识项视图处理组件"""
    # 关联数据查询结果集
    queryset = KnowledgeItem.objects.all()
    # 关联数据序列化组件
    serializer_class = KnowledgeSerializer

    def get(self, request, *args, **kwargs):
        """GET请求处理方法"""
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        """POST请求处理方法"""
        return self.create(request, *args, **kwargs)


class KnowledgeDetailView(generics.GenericAPIView,          # 视图组件
                          mixins.RetrieveModelMixin,        # 数据查询组件
                          mixins.UpdateModelMixin,          # 数据更新组件
                          mixins.DestroyModelMixin,):       # 数据删除组件
    # 关联数据查询结果集
    queryset = KnowledgeItem.objects.all()
    # 关联数据序列化组件
    serializer_class = KnowledgeSerializer

    def get(self, request, *args, **kwargs):
        """GET请求处理方法"""
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        """PUT请求处理方法"""
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        """DELETE请求处理方法"""
        return self.destroy(request, *args, **kwargs)

注意使用时,还要继承GenericAPIView,它为其他组件提供了基础功能。其中queryset和serializer_class属性就是供他使用的,用来指定数据查询结果集和使用的序列化组件,方便后续其他方法和组件后续使用。

4.3 类型视图的功能封装

通过mixin组件对项目中常见操作功能进行封装后,视图组件已经得到优化,但是对于常规的操作,不同数据模型对对象的增删改查大同小异,所以Django rest_framework对CRUD再次封装,提供了以下常规视图组件类型:

  1. generics.CreateAPIView:创建对象视图组件类型。
  2. generics.ListAPIView:查看对象列表视图组件类型。
  3. generics.RetrieveAPIView:查看对象详情视图组件类型。
  4. generics.UpdateAPIView:更新对象信息视图组件类型。
  5. generics.DestroyAPIView:删除对象视图组件类型。
  6. generics.ListCreateAPIView:查看列表及新增数据视图组件类型。
  7. generics.RetrieveUpdateAPIView:查看对象详情和更新对象信息视图组件类型。
  8. generics.RetrieveDestroyAPIView:查看对象详情和删除对象视图组件类型。
  9. generics.RetrieveUpdateDestroyAPIView:查询、更新、删除对象视图组件类型。

示例:

重构knowledge子项目的视图views.py,代码如下:

from rest_framework import generics
from .serializers import KnowledgeSerializer
from .models import KnowledgeItem


class KnowledgeView(generics.ListCreateAPIView):
    """知识项视图处理组件"""
    # 指定查询结果集
    queryset = KnowledgeItem.objects.all()
    # 指定序列化组件
    serializer_class = KnowledgeSerializer

class KnowledgeDetailView(generics.RetrieveUpdateDestroyAPIView):
    """知识项删改查处理组件"""
    # 指定查询结果集
    queryset = KnowledgeItem.objects.all()
    # 指定序列化组件
    serializer_class = KnowledgeSerializer

5.身份认证和权限管理

新建一个子项目,用于演示本节内容:

# 创建knowledge子项目
cd tutorial/
django-admin startapp articles

创建数据模型:

from django.db import models
from django.contrib.auth.models import User
from uuid import uuid4


class Article(models.Model):
    """文章数据类型"""
    id = models.UUIDField(verbose_name="文章编号", primary_key=True, default=uuid4)
    title = models.CharField(verbose_name="文章标题", max_length=100)
    content = models.TextField(verbose_name="文章内容")
    publish_time = models.DateTimeField(verbose_name="发表时间", auto_now_add=True)
    update_time = models.DateTimeField(verbose_name="修改时间", auto_now=True)
    user = models.ForeignKey(verbose_name="作者", to=User, related_name='articles', on_delete=models.CASCADE)

创建序列化模块serializer.py,添加系统用户数据序列化类和文章数据序列化类:

from rest_framework.serializers import (ModelSerializer,
                                        HyperlinkedModelSerializer,
                                        PrimaryKeyRelatedField,
                                        ReadOnlyField)
from django.contrib.auth.models import User
from .models import Article


class UserSerializer(HyperlinkedModelSerializer):
    """用户数据序列化组件"""
    # 关联文章序列化数据
    articles = PrimaryKeyRelatedField(many=True, queryset=Article.objects.all())

    class Meta:
        # 关联数据模型
        model = User
        # 关联属性字段
        fields = ('id', 'username', 'email', 'articles')


class ArticleSerializer(HyperlinkedModelSerializer):
    """文章数据序列化组件"""
    user = ReadOnlyField(source='user.username')
    class Meta:
        # 关联数据模型
        model = Article
        # 关联数据属性字段
        fields = ('id', 'title', 'content', 'user')

视图处理模块,articles/views.py,代码如下:

from rest_framework import status, generics, permissions
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.reverse import reverse
from django.contrib.auth.models import User

from .models import Article
from .serializers import UserSerializer, ArticleSerializer
from .permissions import IsOwnerPermission


##################################################################
#  基于APIView视图类 构建视图组件
##################################################################
class UserListView(generics.ListCreateAPIView):
    """用户列表视图组件"""
    # 视图结果集
    queryset = User.objects.all()
    # 指定序列化类型
    serializer_class = UserSerializer


class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
    """用户详情操作视图组件"""
    # 视图结果集
    queryset = User.objects.all()
    # 指定序列化类型
    serializer_class = UserSerializer


class ArticleView(generics.ListCreateAPIView):
    """文章列表查看"""
    # 指定数据查询集
    queryset = Article.objects.all()
    # 指定序列化类型
    serializer_class = ArticleSerializer


class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
    """文章数据详情操作"""
    # 指定数据查询集
    queryset = Article.objects.all()
    # 指定序列化类型
    serializer_class = ArticleSerializer

然后自行添加一些数据,下面进行权限讲解。

5.1 权限限制

Django rest_framework提供了内建的权限认证模块 rest_framework.permissions。

常用的认证类如下:

  • permissions.IsAuthenticated:验证当前用户是否是Authenticated用户。
  • permissions.IsAdminUser:验证当前用户是否是admin用户。
  • permissions.IsAdminUser:验证当前用户是否是admin用户。
  • permissions.IsAuthenticatedOrReadOnly:认证的用户可以完全操作,否则只能get读取。

修改articles/views.py,代码如下:

from rest_framework import status, generics, permissions
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.reverse import reverse
from django.contrib.auth.models import User

from .models import Article
from .serializers import UserSerializer, ArticleSerializer
from .permissions import IsOwnerPermission


##################################################################
#  基于APIView视图类 构建视图组件
##################################################################
class UserListView(generics.ListCreateAPIView):
    """用户列表视图组件"""
    # 视图结果集
    queryset = User.objects.all()
    # 指定序列化类型
    serializer_class = UserSerializer


class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
    """用户详情操作视图组件"""
    # 视图结果集
    queryset = User.objects.all()
    # 指定序列化类型
    serializer_class = UserSerializer
    # 权限设置
    permission_classes = (permissions.IsAuthenticated,)


class ArticleView(generics.ListCreateAPIView):
    """文章列表查看"""
    # 指定数据查询集
    queryset = Article.objects.all()
    # 指定序列化类型
    serializer_class = ArticleSerializer
    # 权限设置
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)


class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
    """文章数据详情操作"""
    # 指定数据查询集
    queryset = Article.objects.all()
    # 指定序列化类型
    serializer_class = ArticleSerializer
    # 权限设置
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, )

5.2 身份认证API

上面添加身份认证后,需要身份认证通过才能访问接口数据。

但是我们也可以添加用于访问所有路由数据的子路由,方便用户看到所有的子路由。

在主项目urls.py文件添加路由代码如下:

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('quickstart/', include('quickstart.urls')),
    path('knowledge/', include('knowledge.urls')),
    path('articles/', include('articles.urls')),
  	# 添加身份认证管理子路由
    path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
]

在Django rest_framework框架的子路由中,包含了如下两个路由:

  • api-auth/login/:用于用户身份认证、登录的路由;
  • api-auth/logout/:用于已认证、登录的用户退出的路由。

启动项目,访问http://127.0.0.1:8000/api-auth/login/,可以看到如下的登录页面:

在这里插入图片描述

登录后,直接访问http://127.0.0.1:8000/articles/,可以查看文章子项目下所有路由,如下:

在这里插入图片描述

无论是否添加了权限认证的视图组件,都可以访问到数据。

5.3 自定义认证权限

有些接口需求,比如项目中指允许发表文章的用户修改删除自己的文章,其他用户只能查看文章,这时候框架默认权限无法操作,就需要自定义权限。

Django rest_framework框架提供了permissions.BasePermission来让开发自定义权限策略。该模块主要提供了两个权限认证方法:

  • has_permission(self, request, view):判断用户是否拥有访问视图组件中的类型/函数的权限。
  • has_object_permission(self, request, view, obj):判断用户是否拥有访问视图组件中的类型/函数或操作对象的权限。

示例:

在前面articles子项目中,创建权限认证模块permissions.py,添加代码如下:

from rest_framework.permissions import BasePermission, SAFE_METHODS


class IsOwnerPermission(BasePermission):
    """自定义权限"""

    def has_object_permission(self, request, view, obj):
        """判断对于指定对象Obj的操作权限"""
        if request.method == SAFE_METHODS:
            # 判断请求方式是GET/HEAD/OPTIONS安全请求,直接返回True
            return True
        # 验证操作文章对象的用户是否发表文章的用户
        return obj.user == request.user

然后修改视图组件的文章视图,添加我们自定义的权限,代码如下:

class ArticleView(generics.ListCreateAPIView):
    """文章列表查看"""
    # 指定数据查询集
    queryset = Article.objects.all()
    # 指定序列化类型
    serializer_class = ArticleSerializer
    # 权限设置
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)


class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
    """文章数据详情操作"""
    # 指定数据查询集
    queryset = Article.objects.all()
    # 指定序列化类型
    serializer_class = ArticleSerializer
    # 权限设置
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerPermission)

6.接口文档

在写完后端接口后,为针对不同客户端进行数据接口的统一管理,后期进行项目交接时提供完整的接口文档即可。

为此,可以专门定义一个视图函数,用于管理项目中指定数据的接口信息。

编辑articles/views.py,如下:

# 添加此路由函数
@api_view(["GET"])
def api_root(request, format=None):
    return Response({
        'users':reverse('articles:user_list', request=request, format=format),
        'articles':reverse('articles:article_list', request=request, format=format),
    })

然后重构路由模块articles/urls.py:

from django.urls import path, include

from . import views

app_name = "articles"

urlpatterns = [
    path("", views.api_root),
    path("users/", views.UserListView.as_view(), name='user_list'),
    path("users/<int:pk>/", views.UserDetailView.as_view(), name='user_detail'),
    path("articles/", views.ArticleView.as_view(), name='article_list'),
    path("articles/<uuid:pk>/", views.ArticleDetailView.as_view(), name='article_detail'),
]

这样启动项目,访问文章数据接口,可以看到具体的接口信息。

7.视图集及路由配置

除了上面说到的Django rest_framework内建的generic模块提供的简洁的视图操作方式,还提供了更加高度抽象的视图集ViewSets,它与组件 rest_framework.urls.routers配合,实现了数据接口的自动封装和数据请求的自动处理。

ViewSets组件中,不再提供如get、post等类似的请求处理方法,而是在操作过程中由路由模块动态地将ViewSets组件绑定到请求方式。

下面将我们的articles子项目重构使用视图集的方式。

1.视图处理组件

首先使用ViewSets重构视图集组件,编辑articles/views.py,如下:

from rest_framework import viewsets, permissions
from django.contrib.auth.models import User

from .serializers import UserSerializer, ArticleSerializer
from .models import Article
from .permissions import IsOwnerPermission


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """用户视图集"""
    # 指定查询结果集
    queryset = User.objects.all()
    # 指定序列化组件
    serializer_class = UserSerializer

    
class ArticleViewSet(viewsets.ModelViewSet):
    """文章视图集"""
    # 指定查询结果集
    queryset = Article.objects.all()
    # 指定序列化组件
    serializer_class = ArticleSerializer
    # 指定权限操作
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerPermission)

如上,使用viewsets.ReadOnlyModelViewSet替换原来的UserListView和UserDetailView两个视图组件。

同样的,使用viewsets.ModelViewSet构建的数据访问视图集,涵盖了以前GET、POST、PUT、DELETE的所有增删改查操作。

2.路由

接着完成路由模块定义,编辑articles/urls.py,如下:

from django.urls import path, include
from rest_framework import renderers

from . import views

app_name = "articles"

# 用户视图集底层请求构建
user_list = views.UserViewSet.as_view({
    'get': 'list'
})
user_detail = views.UserViewSet.as_view({
    'get': 'retrieve'
})
# 文章视图集底层请求构建
article_list = views.ArticleViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
article_detail = views.ArticleViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
# 将视图集构建对象,映射到路由关系中
urlpatterns = [
    path("", views.api_root),
    path("users/", user_list, name="user_list"),
    path("users/<int:pk>/", user_detail, name="user_detail"),
    path("articles/", article_list, name="article_list"),
    path("articles/<uuid:pk>/", article_detail, name="article_detail"),
]

上面的代码中,显示的指定了对于不同的请求方式绑定的操作,也就是框架自动完成了客户端的请求地址和视图集组件之间的路由。

但是上述是为了我们方便理解视图集是如何区分不同请求方式而这么写的,实际中,一般会通过框架内建的路由模块直接绑定视图集。重新写代码如下:

from django.urls import path, include
from rest_framework import renderers

from . import views

app_name = "articles"

##################################################################
#  基于ViewSets视图集 构建路由关系【常规】
##################################################################
from rest_framework import routers

# 构建路由对象
router = routers.DefaultRouter()
# 挂载注册视图集
router.register(r'users', views.UserViewSet)
router.register(r'articles', views.ArticleViewSet)

# 添加路由映射
urlpatterns = [
    path("", include(router.urls))
]

这样针对不同的请求方式的数据操作,由框架按照内建的通用约定方式进行了自动处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/157253.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DMIPS, FLOPS, OPS概念

DMIPS DMIPS(Dhrystone Million Instructions executed Per Second)&#xff1a;Dhrystone是测量处理器运算能力的最常见基准程序之一&#xff0c;常用于处理器的整型运算性能的测量。Dhrystone是一种整数运算测试程序。换句话说&#xff0c;就是使用Dhrystone这种程序在不同的…

【云原生 | 52】Docker三剑客之Docker Compose第三节

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

FineReport填报报表

二次确认&#xff0c;删除行&#xff1a;参考&#xff1a; JS实现删除时二次确认- FineReport帮助文档 - 全面的报表使用教程和学习资料JS实现记录填报操作- FineReport帮助文档 - 全面的报表使用教程和学习资料确认后直接校验提交// 二次确认 var cell this.options.location…

开始安装Domino 12.0.2

大家好&#xff0c;才是真的好。 上周我们话题是NotesDomino12.0.2产品发布&#xff0c;主要说到了Domino12.0.2的新特性&#xff0c;新特性很多&#xff0c;要用很多篇来进行测试和说明。 今天我们主要谈谈Domino 12.0.2的系统要求和安装等。 首先&#xff0c;Domino12.0.2…

一、初识FreeRTOS之FreeRTOS简介

目录 一、什么是FreeRTOS&#xff1f; 二、为什么选择FreeRTOS&#xff1f; 三、FreeRTOS的特点 四、FreeRTOS资料与源码下载 五、FreeRTOS源码文件介绍 一、什么是FreeRTOS&#xff1f; Free即免费的&#xff0c;RTOS的全称是Real time operating system,中文就是实时操作…

python数据结构(一):字符串

一、字符串的格式化输出 1.1、格式化运算符 print("我跑完了第" str(lap 1) "圈")上面这段输出的代码使用了两个加号做了字符串拼接&#xff0c;并且将整形转换成了字符串。也可以使用一种更好的办法&#xff0c;格式化输出来打印这句话。 print(&quo…

xilinx srio ip学习笔记之再识srio

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 xilinx srio ip学习笔记之再识srio前言SRIO的理解IP核的理解前言 这段时间&#xff0c;随着对SRIO的学习&#xff0c;又有了更深的一点认识&#xff0c;不像一开始这么慌张了…

年终汇报工作,如何用项目管理工具展现成果

据报道&#xff0c;2022年11月20日的一次京东内部会议上&#xff0c;刘强东痛批京东中高层管理人员&#xff0c;表示部分高管醉心于 PPT 和奇妙词汇&#xff0c;或吹得天花乱坠但是执行一塌糊涂。 不可否认&#xff0c;刘强东提到的现象&#xff0c;的确是当今众多互联网大厂和…

基于frp实现外网访问个人本地服务器

适用对象想要通过frp实现内网服务被外网访问的人。关键词描述内网&#xff1a;内网指的是局域网&#xff0c;几台或者几十台电脑之间互访&#xff0c;也叫私网。外网&#xff1a;指的是我们上的Internet网络&#xff0c;也叫公网。需要具备的知识基础和条件1&#xff1a;外网服…

Java异常分类常见使用场景

今天在自己实现RxJava框架时&#xff0c;发现一些参数异常、流关闭异常等&#xff0c;Rxjava框架是会抛出相应的异常的&#xff0c;所以自己编写实现这块源码的时候&#xff0c;渐渐的也需要使用到这些知识&#xff0c;这里对这块做一下回顾总结。 使用 我们代码编写实现中&am…

开年喜讯!知道创宇一连斩获2022年度“IT168技术卓越奖”三项大奖

近日&#xff0c;业界知名IT垂直门户媒体IT168发布“2022年度IT168技术卓越奖”获奖名单&#xff0c;知道创宇凭借强大的技术优势与出色的产品能力脱颖而出&#xff0c;一举斩获网络安全领域三项大奖&#xff1a; 知道创宇创始人、CEO赵伟获评“数字化转型领军人物” ScanV-互…

【C++】优先级队列priority_queue/仿函数(函数对象)

这里写目录标题一.优先级队列1.优先级队列的介绍2.priority_queue的定义与使用二.仿函数/函数对象三.优先级队列的模拟实现一.优先级队列 1.优先级队列的介绍 1&#xff09;注意优先级队列和队列不是一个东西&#xff0c;队列是容器&#xff0c;优先级队列是一种容器适配器&am…

服务监控之promethues+grafana,直接送你上大师,这还不上热门吗

最近的项目需要上监控&#xff0c;虽然之前也是使用这个方案&#xff0c;但是作为使用者一直没有太关注细节&#xff0c;也没有真正的去部署过&#xff0c;刚好凑着这次机会&#xff0c;彻底掌握下这套监控系统 1、监控系统架构 监控的架构这个图几乎每个文章都有&#xff0c…

学习JS,实现自动打字机动效

前几天遇到一个需求&#xff0c;产品告诉我说&#xff0c;希望这些字可以像自动打字那样&#xff0c;一个一个的出来&#xff0c;于是在完成需求的同时&#xff0c;顺便把这个方法记录出来&#xff0c;看大家是否也需要。 目录 1、实现思路 2、html布局和css样式 3、预定义…

【数据库】什么是关系型数据库和非关系型数据库

数据库分类关系型数据库非关系型数据库键值对存储数据库列存储数据库搜索引擎数据库面向文档数据库图形数据库数据库优缺点应用程序都离不开数据库&#xff0c;那不同的数据结构&#xff0c;就会存放在不同的数据数据库中&#xff0c;所以数据库按数据结构分为关系型数据库和非…

spring事务失效的一些场景

1、 Transactional 只能作用在public修饰的方法上 spring事务的实现AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断&#xff0c;如果目标方法不是public&#xff0c;则TransactionAttribute返回null&#xff0c;即不支持事务。 2…

ORB-SLAM3算法和代码学习——跟踪参考关键帧TrackReferenceKeyFrame

0总述 无论是跟踪恒速运动模型还是跟踪参考关键帧&#xff0c;本质上都是基于帧间匹配跟踪。 跟踪恒速模型是当前帧和上一帧之间的匹配&#xff0c;使用基于恒速模型计算得到的位姿作为优化的初始位姿&#xff0c;基于网格和搜索半径寻找匹配关系。 跟踪参考关键帧是当前帧和…

SpringCloudAlibabaSentinel实现网关动态限流

目录 1.SpringCloudAlibabaSentinel实现网关动态限流 1.概念和来历 2.概览及控制台搭建 3.控制台有哪些能力 4.功能及设计理念 5.限流的几种方法 2.SpringCloud Alibaba Sentinel 的降级功能 1.yml中添加配置 2.编写配置类 3.编写兜底工具类 3.Sentinel还对Feigin实…

代码整洁之道,好的代码就是为了更美好的生活

概述 美国童子军有一条简单的军规&#xff1a;让营地比你来时更干净。当梳理代码时&#xff0c;坚守此军规&#xff1a;每次 review 代码&#xff0c;让代码比你发现它时更整洁。 一位大神说过&#xff1a;“衡量代码质量的唯一有效标准&#xff1a;WTF/min”&#xff0c;并配…

14.Isaac教程--Jetbot应用示例

Jetbot应用示例 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 本节介绍如何将 Isaac SDK 与 NVIDIA 新的高性能模拟平台 Omniverse 集成&#xff0c;以让 Jetbot 在模拟中跟随球。 本节作为使用三个 Jetbot 应用程序进入 Omniverse 和 Isaac …