如果不需要序列化类,可在长注释里写参数(不同api文档写法不同,以下为swagger)1
2
3
4
5
6
7
8
9
10"""
<描述>
---
parameters:
- name: mobile_phone
required: true
type: string
description: 手机号
"""
mobile_phone = request.data.get('mobile_phone')
序列化器中,如果想拿到request中的参数,则可1
2
3
4def validate(self, attrs):
code = attrs.get("code")
user = self.context['request'].user
...
select_related()
返回一个queryest,执行时它沿着外键关系查询关联对象的数据。
它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。
select_related() 可用于任何对象的查询集
filter()和select_related顺序不重要,以下等同1
2Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
也可以缓存一个关联之下的关联1
2
3
4
5
6
7
8class City(models.Model):
pass
class Person(models.Model):
hometown = models.ForeignKey(City)
class Book(models.Model):
author = models.ForeignKey(Person)
1 | b = Book.objects.select_related('author__hometown').get(id=4) |
将缓存关联的Person 和关联的 City
也可以反向引用,可使用关联对象字段的related_name。,不要指定字段的名称。
调用不带参数的select_related(),select_related(None)它将查找能找到的所有不可为空外键 —— 可以为空的外键必须明确指定。
POST:新增。
GET:读取。
PUT:更新。
DELETE:删除。
PATCH:部分更新。
PUT和POST的区别为,PUT方法是幂等的(作用在任一元素两次后和其作用一次的结果相同,即请求成功执行所得到的的结果不依赖于该方法被执行的次数。)
例:在一个支付系统中,一个api的功能是创建收款金额二维码,它和金额相关,每个用户可以有多个二维码,如果连续调用则会创建新的二维码,这个时候就用POST
PATCH 部分更新,即如果有内容参数没有传,就不会被更新
API视图
ViewSet
1 | viewsets.ModelViewSet(mixins.CreateModelMixin, |
默认包括创建、查看、更新、删除、列表
create(), retrieve(), update(), partial_update(), destroy() and list()
perform_create创建方法
1 | viewsets.ReadOnlyModelViewSet(mixins.RetrieveModelMixin, |
只读,默认包括retrieve()和list()方法
1 | viewsets.GenericViewSet(ViewSetMixin, generics.GenericAPIView): |
默认不提供任何操作,需自己编写,但包括基本的通用视图行为,例如 get_object
和get_queryset
方法。(通常会使用提供默认行为的现有基类,而不是自己编写)
1 | viewsets.ViewSet(ViewSetMixin, views.APIView): |
默认不提供任何操作
ViewSet视图如果需要可以绑定到单独的视图当中去
1 | user_list = UserViewSet.as_view({'get': 'list'}) |
但通常不这样用,而是用用路由器注册视图,并允许自动生成urlconf
1 | router = DefaultRouter() |
REST框架附带的默认路由器将为标准的create / retrieve / update / destroy样式操作提供路由
如果您需要路由到特殊方法,则可以使用@detail_route或@list_route装饰器将其标记为需要路由。@detail_route装饰器在其URL模式中包含pk,旨在用于需要单个实例的方法。 @list_route装饰器适用于在对象列表上操作的方法。
比如:
1 | class UserViewSet(viewsets.ModelViewSet): |
装饰器也可额外设置仅为路由视图设置的额外参数
1 | @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) |
装饰器默认路由GET请求,但也可以通过使用methods参数来接受其他http方法
1 | @detail_route(methods=['post', 'delete']) |
有俩新操作将可用
^users/{pk}/set_password$
/and ^users/{pk}/unset_password/$
分析:
使用ViewSet类比之view类有两个主要优点:
- 重复的逻辑可组成一个类,比如只需要指定一次queryset,并且它将被跨多个视图使用。
- 通过使用路由器,我们不再需要处理连接自己的URL。
使用常规视图和URL confs更加明确,并为您提供更多的控制。
1 | GenericAPIView(views.APIView) |
所有其他通用视图的基类
APIView
REST框架提供了一个APIView类,它将Django的View类子类化。
APIView与常规的View的不同:
- 传递给处理程序方法的请求将是REST框架的Request实例,而不是Django的HttpRequest实例。
- 处理器方法可能返回REST框架的响应,而不是Django的HttpResponse。该视图将管理内容协商,并根据响应设置正确的渲染器。
- 任何APIException异常将被捕获并调解为适当的响应。
- 传入请求将被认证,并且在将请求发送给处理程序方法之前,将运行适当的权限和/或throttle checks。
@api_view()@api_view(http_method_names=['GET'], exclude_from_schema=False)
如果要编写一个非常简单的视图,比如返回一些数据1
2
3
4
5from rest_framework.decorators import api_view
@api_view()
def hello_world(request):
return Response({"message": "Hello, world!"})
默认只接受GET方法, 如果要指定视图允许的方法:1
2
3
4
5@api_view(['GET', 'POST'])
def hello_world(request):
if request.method == 'POST':
return Response({"message": "Got some data!", "data": request.data})
return Response({"message": "Hello, world!"})
要覆盖默认设置,REST框架提供了一组可以添加到您的视图的其他装饰器。这些必须来自@api_view装饰器1
2
3
4
5
6
7class OncePerDayUserThrottle(UserRateThrottle):
rate = '1/day'
@api_view(['GET'])
@throttle_classes([OncePerDayUserThrottle])
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})
GenericAPIView
GenericAPIView
Mixins:ListModelMixin、CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin
View Classes:CreateAPIView、ListAPIView、RetrieveAPIView、DestroyAPIView、UpdateAPIView、ListCreateAPIView、RetrieveUpdateAPIView、RetrieveDestroyAPIView、RetrieveUpdateDestroyAPIView
1 | class UserList(generics.ListCreateAPIView): |
简单的情况可直接用url1
url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
GenericAPIView
属性
基础配置queryset
:或者用get_queryset()
覆盖。如果覆盖视图方法,调用get_queryset()不是直接访问此属性很重要,因为queryset将被评估一次,并且这些结果将被缓存为所有后续请求。serializer_class
:用于验证和反序列化输入以及序列化输出的serializer类。通常,您必须设置此属性,或覆盖get_serializer_class()方法。lookup_field
:应用于执行单个模型实例的对象查找的模型字段。默认为“pk”。注意,当使用超链接的API时,如果需要使用自定义值,则需要确保API视图和序列化器类都设置查找字段。lookup_url_kwarg
:用于对象查找的URL关键字参数。 URL conf应包含与该值相对应的关键字参数。如果取消设置,则默认使用与lookup_field相同的值
分页Paginationpagination_class
:分页列表结果时应使用的分页类。默认值与DEFAULT_PAGINATION_CLASS设置相同,即’rest_framework.pagination.PageNumberPagination’,设置pagination_class = None将禁用此视图上的分页。
过滤filter_backends
:应用于过滤查询集的过滤器后端类的列表。默认值与DEFAULT_FILTER_BACKENDS设置相同。
方法
def get_queryset(self):查询集方法。
get_object(self):得到对象方法。
filter_queryset(self, queryset):给定一个查询器,使用任何过滤器后端进行过滤,返回一个新的查询器。1
2
3
4
5
6
7
8
9
10
11
12def filter_queryset(self, queryset):
filter_backends = (CategoryFilter,)
if 'geo_route' in self.request.query_params:
filter_backends = (GeoRouteFilter, CategoryFilter)
elif 'geo_point' in self.request.query_params:
filter_backends = (GeoPointFilter, CategoryFilter)
for backend in list(filter_backends):
queryset = backend().filter_queryset(self.request, queryset, view=self)
return queryset
get_serializer_class(self):返回应该用于序列化程序的类。
以下方法由mixin类提供,并提供容易地覆盖对象保存或删除行为。perform_create(self, serializer)
- 在保存新对象实例时由CreateModelMixin调用。perform_update(self, serializer)
- 在保存现有对象实例时由UpdateModelMixin调用。perform_destroy(self, instance)
- 删除对象实例时由DestroyModelMixin调用。
这些特别适用于设置请求中隐含的属性,但不是请求数据的一部分。例如,您可以根据请求用户或基于URL关键字参数在对象上设置属性。
对于添加在保存对象之前或之后发生的行为(例如发送确认或记录更新)也特别有用。
1 | def perform_create(self, serializer): |
通常您不需要覆盖以下方法,尽管如果使用GenericAPIView编写自定义视图,则可能需要调用它们。
get_serializer_context(self)
:返回包含应提供给序列化程序的额外上下文的字典。默认为包含'request'
, 'view'
和'format'
键。get_serializer(self, instance=None, data=None, many=False, partial=False)
:返回一个序列化器实例。get_paginated_response(self,data)
:返回分页样式的Response对象。paginate_queryset(self, queryset)
:如果需要,请分页查询器,返回页面对象,如果未为此视图配置分页,则为无。filter_queryset(self,queryset)
:给定一个查询器,使用任何过滤器后端进行过滤,返回一个新的查询器。