Loading... ## 序列化 ```python from rest_framework import serializers from .models import Hosts, HostsInfo class HostsInfoSerializer(serializers.ModelSerializer): class Meta: model = HostsInfo fields = ('position', 'is_used') class HostsSerializer(serializers.ModelSerializer): # info = HostsInfoSerializer() class Meta: # 操作的模型 model = Hosts # 序列化后输出的字段 fields = '__all__' # 额外字段, 在序列化的时候不会体现出来 extra_kwargs = { 'ip': {'min_value': 0, 'max_value': 1000} } # 只读 => 序列化 (不允许反序列化) read_only_fileds = ['ip', 'serial_number'] ``` ### 序列化 > Serializer(instance=None, data=None, **kwargs) ```python from .serializers import HostsSerializer from .models import Hosts host = Hosts.objects.get(id=1) # HostsInfoSerializer(实例, many=True) HostsInfoSerializer(host).data # 可获取到Json数据 # 当实例是一个QuerySet的时候需要加上many=True HostsInfoSerializer(Hosts.objects.all(). many=True).data ``` ### 反序列化 ```python from hosts.models import Hosts from hosts.serializers import HostsSerializer """ 流程 拿到前端传入的数据 --> 写入到序列化器的data属性 --> 调用序列化器的.is_valid()进行校验 --> 调用序列化器的save()方法 """ data = { 'ip': '192.168.1.1', 'serial_number': '12334', 'asset_number': '12334', } s = HostsSerializer(data=data) s.is_valid() # => 无效返回False, 反之为True # s.is_valid(raise_exception=True) # => 直接抛出错误信息 s.errors # => 可以获取到校验失败的错误信息 s.save() # => 保存到模型 他可能执行 .create 或 .update 方法 """ HostsSerializer(instance=MODEL, data=data) # 同时具备instance和data, 那么save会执行update # 只有data, 那么save执行的是create # context:dict 额外数据 """ # 获取反序列化的数据 s.validated_data # => OrderDict ``` 在基类`Serializer`中, 没有实现`update`方法, 如果继承自`Serializer`, 需要自己实现`update`方法 ```python class HostsSerializer(serializers.Serializer): # info = HostsInfoSerializer() ip = serializers.CharField(label='ID', read_only=True) serial_number = serializers.CharField(label='序列号', validators=[check, ]) asset_number = serializers.CharField(label='资产编码') is_delete = serializers.BooleanField(label='逻辑删除') class Meta: model = Hosts fields = '__all__' @classmethod def validate_serial_number(cls, value): if len(value) < 5: raise serializers.ValidationError('序列号长度不足5') return value def validate(self, attrs: dict): # 联合校验 print(attrs) # 所有数据, 可以对多个字段做校验 return super(HostsSerializer, self).validate(attrs) def update(self, instace, validate_data): # validate_data就是 self.validate_data # instace 就是 self.instance pass def create(self, validated_data): pass ``` ### 追加额外的校验逻辑 ```python def check(val): if len(val) < 5: raise serializers.ValidationError('长度小于5') return val class HostsSerializer(serializers.ModelSerializer): # info = HostsInfoSerializer() ip = serializers.CharField(label='ID', read_only=True) # 也可以在字段加入validators=[校验函数, 校验函数,] serial_number = serializers.CharField(label='序列号', validators=[check, ]) asset_number = serializers.CharField(label='资产编码') is_delete = serializers.BooleanField(label='逻辑删除') class Meta: model = Hosts fields = '__all__' @classmethod def validate_serial_number(cls, value): if len(value) < 5: raise serializers.ValidationError('序列号长度不足5') return value def validate(self, attrs: dict): # 联合校验 print(attrs) # 所有数据, 可以对多个字段做校验 return super(HostsSerializer, self).validate(attrs) ``` ## 视图 ### Request <div class="tip inlineBlock warning"> `REST`中的`Request`对象不再是`Django`默认的的`HttpRequest`对象, 而是`REST`提供了基于Django HttpRquest扩展的`Request` </div> REST Framework提供了**Parser**解析器, 在接收到请求后会自动根据`Content-Type`指明的请求数据进行解析, 解析为类字典保存到`Request`中, 这样我们就可以用统一的方法读取请求中的数据 常用属性: - data: 请求的数据 - query_params: 查询字符串 ### Response > rest_framework.response.Response REST Framework提供了响应类`Response`,使用该类构造响应对象时, 响应的具体数据内容会被转换为(`reader`渲染)成符合前端需求的类型 RESET Framework提供了`Renderer`渲染器, 用来根据请求头中的`Accept`(接收数据类型声明)来自动转换响应数据到对应的格式, 如果前端请求中未进行`Accept`声明, 则会采用默认方式处理响应数据, 我们可以通过配置来修改默认响应格式 ```python # setting.py REST_FRAMEWORK = { # 定义默认的渲染器 'DEFAULT_RENDERER_CLASSES': ( 'utils.render.ITJsonRenderer', 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ), } ``` **响应构造方法** ```python Response(data, status=None, template_name=None, headers=None, content_type=None) """ data: 为响应准备的序列化处理后的数据 status: 状态码, 默认是200 template_name: 模版名称, 如果使用HTMLRenderer需要指明该参数 header: 响应头 content_type: 响应数据类型, 通常无需床底, REST会根据前端需要的数据类型自动设置 """ ``` 常用属性: - data: 序列化后的数据, 还没有被renderer处理的数据 - status_code: 状态码 - content: 经过renderer处理的数据 **在Response中,REST将常用的状态码定义为了常量** ```python from rest_framework import status # 消息告知 1XX HTTP_100_CONTINUE = 100 HTTP_101_SWITCHING_PROTOCOLS = 101 # 成功 2XX 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 # 资源重定向 3XX 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错误 4XX 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_422_UNPROCESSABLE_ENTITY = 422 HTTP_423_LOCKED = 423 HTTP_424_FAILED_DEPENDENCY = 424 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 # 服务器错误 5XX 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_507_INSUFFICIENT_STORAGE = 507 HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 ``` ### 两个视图基类 #### APIView ```python from rest_framework.views import APIView ``` `APIView`是`REST`提供的所有视图的基类, 继承自`Django`的`View` `APIView`与`View`的不同之处 - 传入到视图方法中的是`REST`的`Request`对象, 而不是`Django`的`HttpRequest`对象 - 视图方法可以放回`REST`的`Rsponse`对象, 视图会为响应数据设置(`redner`)符合前端要求的格式 - 任何`APIException`异常都会被捕获到, 并处理成合适的响应信息 - 在进行`dispatch`分发前, 会对请求进行身份认证/权限检查, 流量控制 支持定义的属性 - `authentication_classes`列表或元组, 身份认证类 - `permission_classes`列表或元组, 权限检查类 - `throttle_classes` 列表或元组, 流量控制类 在`APIView`中仍以常规的类视图定义方法来实现`get(), post()`等其他请求方法 举例: ```python class HostsView(APIView): """列表视图""" def get(self, request: Request, pk=None): if pk: query = HostsSerializer(Hosts.objects.filter(id=pk), many=True) else: query = HostsSerializer(Hosts.objects.all(), many=True) data = { 'code': 200, 'data': query.data } return Response(data) def post(self, requset): pass # 几乎和原生的Django框架使用方法一致 ``` #### GenericAPIView ```python from rest_framework.generics import GenericAPIView ``` 继承自`APIView`,主要增加了操作序列化和数据库查询的方法, 作用是为一下`Mixin`扩展类的执行提供语法资产, 通常在使用时,可以搭配一个或多个`Minin`扩展类. 提供的关于序列化器使用的属性和方法 - 属性 - `serializer_class`: 指明视图的序列化器 - `queryset`: 指明查询集 - `lookup_field`: 默认是`pk`, 在`get_object()`中有是使用到 - 方法 - `get_serializer_class(self)` 返回序列化器类, 默认返回`serialzer_class`, 可以对其进行重写 - `get_serializer(self, *arg, **kwargs)` 获取序列化器, 可像序列化器一样调用它 提供了关于数据库查询的属性和方法 - 属性 - `queryset`指明使用的数据查询集 - 方法 - `get_queryset(self)` 返回视图使用的查询集,主要用来提供给`Mixin`扩展类使用, 是列表视图于详情视图获取数据的基础, 默认返回`queryset`属性, 同样可以重写 - `get_object(self)` 获取单一的数据对象, 如详情访问的模型类对象不存在, 会返回404, 默认会过滤一个`pk`, 如果`pk`存在 - 其他可以设置的属性 - `pagination_class`: 指明分页控制类 - `filter_backends`: 指明过滤控制后端 ### 五个扩展类 ```python from rest_framework import mixins mixins.ListModelMixin # => 这一个主要是返回一个list mixins.CreateModelMixin # => 创建扩展POST mixins.RetrieveModelMixin # => GET 获取单个资源 mixins.UpdateModelMixin # => PUT 修改单个资源 mixins.DestroyModelMixin # =>DELETE 删除单个资源 ``` #### 其他视图 ```python from rest_framework.generics import ListAPIView # 这个视图只提供了查询所有资源 from rest_framework.generics import CreateAPIView # 这个视图只提供了Create资源 from rest_framework.generics import ListCreateAPIView # 这个视图拥有查询所有和新增资源 RetrieveAPIView # 查询单一 DestroyAPIView # 删除单一 ``` #### ModelViewSet ```python from rest_framework.viewsets import ModelViewSet # 继承了五个Mixin扩展和GenericViewSet ``` ### 视图集 #### ViewSet ```python from rest_framework.viewsets import ViewSet ``` 使用视图集`ViewSet`, 可以将一系列逻辑相关的动作放到一个类中 - `list()`提供一组数据 - `retrieve()`提供单个数据 - `create()`创建数据 - `update()`更新数据 - `destory()`删除/销毁数据 `ViewSet`视图集不在实现`get(), post()`等方法, 而是实现动作`action`如`list(), create()`等, 视图集只使用在使用`as_view()`方法到时候, 才会将`action`动作与具体请求方式对应上.如: ```python class HostsView(viewsets.ViewSet): def list(self, request): hosts = Host.objects.all() serializer = HostsSerializer(hosts, many=True) return Response(serializer.data) def retrieve(self, requset, pk=None): try: host = Host.objects.get(id=pk) except Host.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) serializer = HostsSerializer(host) return Response(serializer.data) # 设置路由的时候应该设置如下 urlpatterns = [ # 需要在as_view()中写入一个字典, 定义get/post请求对应的方法 url(r'^hosts/$', HostsView.as_view({'get': 'list'})), ] ``` #### GenericViewSet ```python from rest_framework.viewsets import GenericViewSet # GenericViewSet 继承自 GenericView # 使用方法一致 # as_view的时候指定请求方式对应的方法 ``` ### ModelViewSet ```python from rest_framework.viewsets import ModelViewSet # ModelViewSet继承自GenericViewSet和五个扩展类 # 默认就存在list, update, create, retrieve, destroy ``` ### 在是视图集中添加额外的行为 ```python # 例子 class HostsView(ModelViewSet): """获取最后一个机器""" queryset = Hosts.objects.all() serializer_class = HostsSerializer def latest(self, request): pass urlpatterns = [ # 获取最后一台机器 url(r'^hosts/latest/$', HostsView.as_view({'get': 'latest'})), ] # 简化操作后 # 路由器只能结合视图集使用 from rest_framework.decorators import list_route, detail_route class HostsView(ModelViewSet): """获取最后一个机器""" queryset = Hosts.objects.all() serializer_class = HostsSerializer @list_route(method=['get']) def latest(self, request): pass @detail_route(method=['put']) def read(request): pass urlpatterns = [ # 获取最后一台机器 url(r'^hosts/$', HostsView.as_view()), ] # list_route 列表路由 # -> 如果有pk,路由大概为: /hosts/latest/(?P<pk>\d+)$/ # -> 没有pk, 路由大概为: /hosts/latest/ # detail_route 详情路由 # -> 路由大概为: /hosts/(?P<pk>\d+)$/latest/ ``` ### 分页和过滤 ## 路由 `DefaultRouter`和`SimpleRouter`的区别.当项目跟路由中出现了其他路由, `DefaultRouter`会报错`404`, 也就是`DefaultRouter`会比`SimpleRouter`多生成一个根路由, `SimpleRouter`则不会影响. ## 认证 可以在配置文件中配置全局认证方案 ```python # setting.py # REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', # Session认证 'rest_framework.authentication.BasicAuthentication', # 基本认证 ], } # 这个视图只只会走REST框架视图 ``` 也可以在视图中通过设置`authentication_classess`属性设置 ```python from rest_framework.authentication import SessionAuthentication, BaseAuthentication class UserInfo(APIView): authentication_classes = (SessionAuthentication, BaseAuthentication) # .... # 不过现在主要是使用JWT认证 ``` <div class="tip inlineBlock info"> 认证失败会返回`401 Unauthorized`或`403 Permission Denied` </div> ## 权限 ### 使用 在配置文件中设置默认的权限管理类, 如: ```python # setting.py REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], } # 如果没有指明, 则采用下面的默认配置. 权限指定局部的, 不要全局指定 REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ], } ``` 也可以在视图中通过`permission_classess`设置 ### 提供的权限 - `AllowAny`: 允许所有用户 - `IsAuthenticated`: 仅允许通过认证的永华 - `IsAdmin`: 仅管理员用户 - `IsAuthenticatedOrReadOnly`:认证的用户可以完全操作, 否者只能`get` ### 举例 ```python from rest_framework.permissions import IsAuthenticated class HostsView(ModelViewSet): queryset = Hosts.objects.all() serializer_class = HostsSerializer authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated] # ... ``` ### 自定义权限 ```python class MyPermission(BasePermission): def has_object_permission(self, request, view, obj): """ 是否可以访问数据对象/详情视图 :param request: 请求 :param view: 视图 :param obj: 数据对象 :return: """ return False def has_permission(self, request, view): """ 是否可以访问视图/数据列表 :param request: 请求 :param view: 视图 :return: """ return False ``` 如果全局设置了都必须登陆才能访问视图, 某一个视图不需要登陆 ```python class MyView(APIView): def check_permissions(self, request): """在视图中重写该方法""" pass ``` ## 限流 可以对接口的访问进行一定的访问控制, 以减轻服务器压力 ```python # setting.py REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', # 匿名用户 'rest_framework.throttling.UserRateThrottle', # 登陆用户 ), 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', # 匿名用户 'user': '1000/day', # 登陆用户 }, } ``` `DEFAULT_THROTTLE_RATES`可以使用`second, minute,hour`或`day`来指明周期, 也可以在具体视图中通过`throttle_classess`属性来配置. 如: ```python class MyView(APIView): throttle_classess = [UserRateThrottle] ``` ## 过滤Filtering 对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。 ```bash pip install django-filter ``` 在配置文件中增加过滤后端的设置: ```python # setting.py INSTALLED_APPS = [ ... 'django_filters', # 需要注册应用, ] REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) } ``` 在视图中添加filter_fields属性,指定可以过滤的字段 ```python class BookListView(ListAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer filter_fields = ('btitle', 'bread') # 127.0.0.1:8000/book/?btitle= ``` ## 排序 对于列表数据,REST framework提供了**OrderingFilter** 过滤器来帮助我们快速指明数据按照指定字段进行排序。 #### 使用方法: 在类视图中设置filter_backends,使用`rest_framework.filters.OrderingFilter`过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。 前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。 示例: ```python class BookListView(ListAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer filter_backends = [OrderingFilter] ordering_fields = ('id', 'bread', 'bpub_date') # 127.0.0.1:8000/books/?ordering=-bread ``` ## 分页 REST framework提供了分页的支持。 我们可以在配置文件中设置全局的分页方式,如: ```python REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 # 每页数目 } ``` 也可通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过`pagination_class`属性来指明。 ```python class LargeResultsSetPagination(PageNumberPagination): page_size = 1000 page_size_query_param = 'page_size' max_page_size = 10000 ``` ```python class BookDetailView(RetrieveAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer pagination_class = LargeResultsSetPagination ``` **注意:如果在视图内关闭分页功能,只需在视图内设置** ```python pagination_class = None ``` ### 可选分页器 1) **PageNumberPagination** 前端访问网址形式: ``` GET http://api.example.org/books/?page=4 ``` 可以在子类中定义的属性: * page_size 每页数目 * page_query_param 前端发送的页数关键字名,默认为"page" * page_size_query_param 前端发送的每页数目关键字名,默认为None * max_page_size 前端最多能设置的每页数量 ```python from rest_framework.pagination import PageNumberPagination class StandardPageNumberPagination(PageNumberPagination): page_size_query_param = 'page_size' max_page_size = 10 class BookListView(ListAPIView): queryset = BookInfo.objects.all().order_by('id') serializer_class = BookInfoSerializer pagination_class = StandardPageNumberPagination # 127.0.0.1/books/?page=1&page_size=2 ``` 2)**LimitOffsetPagination** 前端访问网址形式: ``` GET http://api.example.org/books/?limit=100&offset=400 ``` 可以在子类中定义的属性: * default_limit 默认限制,默认值与`PAGE_SIZE`设置一致 * limit_query_param limit参数名,默认'limit' * offset_query_param offset参数名,默认'offset' * max_limit 最大limit限制,默认None ```python from rest_framework.pagination import LimitOffsetPagination class BookListView(ListAPIView): queryset = BookInfo.objects.all().order_by('id') serializer_class = BookInfoSerializer pagination_class = LimitOffsetPagination # 127.0.0.1:8000/books/?offset=3&limit=2 ``` ## 异常处理 ## 自动生成接口文档 最后修改:2021 年 06 月 21 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 2 如果觉得我的文章对你有用,请随意赞赏
4 条评论
哈哈哈,写的太好了https://www.lawjida.com/
《月落玉长河》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/21421.html
看到你的文章,我仿佛感受到了生活中的美好。 https://www.4006400989.com/qyvideo/51920.html
怎么收藏这篇文章?