环境搭建
pip install djangorestframework
添加rest_framework应用
INSTALLED_APPS = [
...
'rest_framework',
]
原生Django实现增删改查逻辑
模型models.py
from django.db import models
# Create your models here.
#定义图书模型类BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期')
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
class Meta:
db_table = 'tb_books' # 指明数据库表名
verbose_name = '图书' # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称
def __str__(self):
"""定义每个数据对象的显示信息"""
return self.btitle
视图views.py:
from django.views import View
from django.http import JsonResponse
import json
from books.models import BookInfo
# Create your views here.
class BooksView(View):
"""
获取所有和保存
"""
def get(self, request):
# 1. 查询所有图书对象
books = BookInfo.objects.all()
# 2. 返回图书数据 [{},{}]
book_list = []
for book in books:
book_list.append(
{
'id': book.id,
'btitle': book.btitle,
'bread': book.bread,
'bcomment': book.bcomment,
'bpub_date': book.bpub_date,
}
)
return JsonResponse(book_list, safe=False)
def post(self, request):
# 1. 获取前端数据
data = request.body.decode()
data_dict = json.loads(data)
# 2. 验证数据
btitle = data_dict.get('btitle')
bpub_date = data_dict.get('bpub_date')
if btitle is None or bpub_date is None:
return JsonResponse({'error': '错误信息'}, status=400)
# 3. 保存数据
book = BookInfo.objects.create(btitle=btitle, bpub_date=bpub_date)
# 4. 返回结果
return JsonResponse(
{
'id': book.id,
'btitle': book.btitle,
'bread': book.bread,
'bcomment': book.bcomment,
'bpub_date': book.bpub_date,
}
)
class BookView(View):
"""
获取单一图书和更新和删除
"""
def get(self, request, pk):
# 1. 查询数据对象
try:
book = BookInfo.objects.get(id=pk)
except:
return JsonResponse({'error': '错误信息'}, status=400)
return JsonResponse(
{
'id': book.id,
'btitle': book.btitle,
'bread': book.bread,
'bcomment': book.bcomment,
'bpub_date': book.bpub_date,
}
)
def put(self, request, pk):
# 1. 获取前端数据
data = request.body.decode()
data_dict = json.loads(data)
# 2. 验证数据
btitle = data_dict.get('btitle')
bpub_date = data_dict.get('bpub_date')
if btitle is None or bpub_date is None:
return JsonResponse({'error': '错误信息'}, status=400)
# 3. 更新数据
try:
book = BookInfo.objects.get(id=pk)
except:
return JsonResponse({'error': '错误信息'}, status=400)
book.btitle = btitle
book.bpub_date = bpub_date
book.save()
# 4. 返回结果
return JsonResponse(
{
'id': book.id,
'btitle': book.btitle,
'bread': book.bread,
'bcomment': book.bcomment,
'bpub_date': book.bpub_date,
}
)
def delete(self, request, pk):
# 1. 获取数据对象
try:
book = BookInfo.objects.get(id=pk)
except:
return JsonResponse({'error': '错误信息'}, status=400)
book.is_delete = True
book.save()
# 2. 返回结果
return JsonResponse({})
下面介绍使用Django REST framework框架后视图的变化
首先,我们需要定义一个序列化器:
序列化器的作用是:1. 进行数据的校验; 2. 对数据对象进行转换
常用字段类型:
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3) 'int' - 如: "123456789012312313134124512351145145114" 4) 'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
选项参数:
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用参数:
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
序列化器serializer.py
from rest_framework import serializers
from books.models import BookInfo
# 自定义序列化器
class BookSerializer(serializers.Serializer):
# 序列化返回字段
# write_only=True --> 该字段只参与反序列化验证过程,不参与序列化返回过程
btitle = serializers.CharField(max_length=20, min_length=5, write_only=True)
bread = serializers.IntegerField(max_value=100, min_value=5)
bpub_date = serializers.DateField()
bcomment = serializers.IntegerField(default=10)
# 单一字段验证
def validate_btitle(self, value):
if value == 'ITCAST':
raise serializers.ValidationError('书名不能是ITCAST')
return value
# 多个字段验证
def validate(self, attrs):
if attrs['bread'] > attrs['bcomment']:
raise serializers.ValidationError('阅读量大于评论量')
return attrs
def create(self, validated_data):
# {'name': 'python'}
# 拆包: name = 'python'
# 保存数据
book = BookInfo.objects.create(**validated_data)
return book
def update(self, instance, validated_data):
# 更新数据
instance.btitle = validated_data['btitle']
instance.bread = validated_data['bread']
instance.save()
return instance
当引入序列化器后,我们视图变化如下:
def post(self, request):
# 1. 获取前端数据
data = request.body.decode()
data_dict = json.loads(data)
# 2. 验证数据
btitle = data_dict.get('btitle')
bpub_date = data_dict.get('bpub_date')
if btitle is None or bpub_date is None:
return JsonResponse({'error': '错误信息'}, status=400)
# 3. 保存数据
book = BookInfo.objects.create(btitle=btitle, bpub_date=bpub_date)
# 4. 返回结果
return JsonResponse(
{
'id': book.id,
'btitle': book.btitle,
'bread': book.bread,
'bcomment': book.bcomment,
'bpub_date': book.bpub_date,
}
)
-------------------------->
def post(self, request):
# 1. 获取前端数据
data = request.body.decode()
data_dict = json.loads(data)
# 2. 验证数据
ser = BookSerializer(data=data_dict)
# 验证方法 raise_exception=True--->检测到错误自动抛出异常并返回
# ser.is_valid(raise_exception=True)
ser.is_valid()
# 获取验证后的字段数据
# print(ser.validated_data)
# 3. 保存数据
ser.save()
# 4. 返回结果
return JsonResponse(ser.data)
接着,我们的视图也会发生相应变化,视图的变化相对复杂。
类视图 - 两个基本类视图(继承自Django的View类的APIView + 继承自APIView的GenericAPIview)+ 五个拓展类(需要配合GenericAPIview使用,继承自Object,分别为:ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin ,DestroyModelMixin )+ 拓展类子类(ListCreateAPIView, ListAPIView, CreateAPIView, DestroyAPIView, RetrieveDestroyAPIView, RetrieveAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, UpdateAPIView)。
视图集 - 两个基本视图集(继承自APIView的ViewSet,继承自GenericAPIview的GenericViewset ) + 两个拓展视图集(ModelViewSet和ReadOnlyModelViewSet)
类视图 - 两个基本类视图
APIView :主要在于Request和Response的区别
原生Django获取前端数据的方法:
data = request.body.decode()
data_dict = json.loads(data)
使用APIView后获取前端数据的方法:
data = request.data
另外响应Response也会不同,原生Django响应数据使用JsonResponse,并且需要手动拼接Json数据
return JsonResponse(
{
'id': book.id,
'btitle': book.btitle,
'bread': book.bread,
'bcomment': book.bcomment,
'bpub_date': book.bpub_date,
}
)
使用APIView后响应Response的方法:
return Response(ser.data)
完整视图函数views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from book_drf.serializer import BookSerializer
from books.models import BookInfo
# Create your views here.
class Books(APIView):
def get(self, request):
# print(request.query_params)
# 1. 查询所有图书对象
books = BookInfo.objects.all()
# many=True ---> 返回多个数据
ser = BookSerializer(books, many=True)
return Response(ser.data)
def post(self, request):
# 1. 获取前端数据
data = request.data
# 2. 验证数据
ser = BookSerializer(data=data)
# 验证方法 raise_exception=True--->检测到错误自动抛出异常并返回
# ser.is_valid(raise_exception=True)
ser.is_valid()
# 3. 保存数据
ser.save()
# 4. 返回结果
return Response(ser.data)
class BookDRFView(APIView):
"""
获取当一和更新和删除
"""
def get(self, request, pk):
# 1. 查询数据对象
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book)
return Response(ser.data)
def put(self, request, pk):
# 1. 获取前端数据
data = request.data
# 2. 验证数据
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book, data=data)
ser.is_valid()
# 3. 更新数据
ser.save()
# 4. 返回结果
return Response(ser.data)
def delete(self, request, pk):
# 1. 获取数据对象
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
book.is_delete = True
book.save()
# 2. 返回结果
return Response({})
GenericAPIview:
- queryset 列表视图的查询集
- serializer_class 视图使用的序列化器
主要区别在于定义类视图时需要声明当前类视图使用的查询集数据,以及当前类视图使用的序列化器
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
另外,在获取查询集中所有数据时使用:
books = self.get_queryset() # 获取查询集中的所有数据
在获取单一数据时使用:
book = self.get_object()
完整的视图views.py:
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from book_drf.serializer import BookSerializer
from books.models import BookInfo
# Create your views here.
class Books(GenericAPIView):
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
def get(self, request):
# 1. 查询所有图书对象
books = self.get_queryset() # 获取查询集中的所有数据
# many=True ---> 返回多个数据
ser = self.get_serializer(books, many=True) # 使用序列化器,获取序列化器对象
return Response(ser.data)
def post(self, request):
# 1. 获取前端数据
data = request.data
# 2. 验证数据
ser = self.get_serializer(data=data)
# 验证方法 raise_exception=True--->检测到错误自动抛出异常并返回
# ser.is_valid(raise_exception=True)
ser.is_valid()
# 获取验证后的字段数据
# print(ser.validated_data)
# 3. 保存数据
ser.save()
# 4. 返回结果
# return JsonResponse(ser.data)
return Response(ser.data)
class BookDRFView(GenericAPIView):
"""
获取当一和更新和删除
"""
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
def get(self, request, pk):
# 1. 查询数据对象
try:
book = self.get_object() # 根据pk值,从查询集中获取指定的单数据对象
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book)
return Response(ser.data)
def put(self, request, pk):
# 1. 获取前端数据
# data = request.body.decode()
# data_dict = json.loads(data)
data = request.data
# 2. 验证数据
try:
book = self.get_object() # 从查询集中获取指定的单数据对象
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book, data=data)
ser.is_valid()
# 3. 更新数据
ser.save()
# 4. 返回结果
return Response(ser.data)
def delete(self, request, pk):
# 1. 获取数据对象
try:
book = self.get_object()
except:
return Response({'error': '错误信息'}, status=400)
book.is_delete = True
book.save()
# 2. 返回结果
return Response({})
类视图 - 五个拓展类
ListModelMixin 列表视图扩展类,提供list(request, *args, **kwargs)
方法快速实现列表视图,返回200状态码。
CreateModelMixin 创建视图扩展类,提供create(request, *args, **kwargs)
方法快速实现创建资源的视图,成功返回201状态码。
RetrieveModelMixin 详情视图扩展类,提供retrieve(request, *args, **kwargs)
方法,可以快速实现返回一个存在的数据对象。如果存在,返回200, 否则返回404。
UpdateModelMixin 更新视图扩展类,提供update(request, *args, **kwargs)
方法,可以快速实现更新一个存在的数据对象。成功返回200,序列化器校验数据失败时,返回400错误。
DestroyModelMixin 删除视图扩展类,提供destroy(request, *args, **kwargs)
方法,可以快速实现删除一个存在的数据对象。成功返回204,不存在返回404。
在实现增删改查的业务逻辑时,定义视图类时,继承的子类由业务逻辑需要来定。比如:
class Books(GenericAPIView, CreateModelMixin, ListModelMixin):
"""获取所有数据对象和增加"""
pass
class BookDRFView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
"""获取单一数据对象、更新和删除"""
pass
视图完整代码views.py
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin
from book_drf.serializer import BookSerializer
from books.models import BookInfo
# Create your views here.
class Books(GenericAPIView, CreateModelMixin, ListModelMixin):
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookDRFView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
"""
获取当一和更新和删除
"""
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
def get(self, request, pk):
return self.retrieve(request, pk)
def put(self, request, pk):
return self.update(request, pk)
def delete(self, request, pk):
return self.destroy(request, pk)
源码分析:以CreateModelMixin为例
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 {}
可以看出CreateModelMixin类实际上封装了:
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
类视图 - 九个拓展类子类
完整视图views.py
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from book_drf.serializer import BookSerializer
from books.models import BookInfo
# Create your views here.
class Books(ListCreateAPIView):
"""获取所有和添加"""
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
class BookDRFView(RetrieveUpdateDestroyAPIView):
"""
获取当一和更新和删除
"""
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
视图集 - 两个基本视图集
ViewSet:继承自APIView
,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
- list() 提供一组数据
- retrieve() 提供单个数据
- create() 创建数据
- update() 保存数据
- destory() 删除数据
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from book_drf.serializer import BookSerializer
from books.models import BookInfo
# Create your views here.
class Books(ViewSet):
def list(self, request):
# 1. 查询所有图书对象
books = BookInfo.objects.all()
# many=True ---> 返回多个数据
ser = BookSerializer(books, many=True)
return Response(ser.data)
def create(self, request):
# 1. 获取前端数据
data = request.data
# 2. 验证数据
ser = BookSerializer(data=data)
# 验证方法 raise_exception=True--->检测到错误自动抛出异常并返回
# ser.is_valid(raise_exception=True)
ser.is_valid()
# 获取验证后的字段数据
# print(ser.validated_data)
# 3. 保存数据
ser.save()
# 4. 返回结果
return Response(ser.data)
class BookDRFView(ViewSet):
"""
获取当一和更新和删除
"""
def retrieve(self, request, pk):
"""获取单一数据"""
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book)
return Response(ser.data)
def update(self, request, pk):
"""更新数据"""
# 1. 获取前端数据
data = request.data
# 2. 验证数据
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book, data=data)
ser.is_valid()
# 3. 更新数据
ser.save()
# 4. 返回结果
return Response(ser.data)
def destroy(self, request, pk):
"""删除单一数据"""
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
book.is_delete = True
book.save()
# 2. 返回结果
return Response({})
路由配置urls.py
urlpatterns = [
url(r'^books_drf/$', viewset_view.Books.as_view({'get': 'list', 'post': 'create'})),
url(r'^books_drf/(?P<pk>\d+)/$', viewset_view.BookDRFView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
GenericViewSet: 继承自GenericAPIView
,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于列表视图与详情信息视图的开发。
完整视图views.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from book_drf.serializer import BookSerializer
from books.models import BookInfo
# Create your views here.
class Books(GenericViewSet):
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
def list(self, request):
# 1. 查询所有图书对象
books = self.get_queryset()
ser = self.get_serializer(books, many=True)
return Response(ser.data)
def create(self, request):
# 1. 获取前端数据
data = request.data
# 2. 验证数据
ser = self.get_serializer(data=data)
# 验证方法 raise_exception=True--->检测到错误自动抛出异常并返回
# ser.is_valid(raise_exception=True)
ser.is_valid()
# 3. 保存数据
ser.save()
# 4. 返回结果
return Response(ser.data)
class BookDRFView(GenericViewSet):
"""
获取当一和更新和删除
"""
def retrieve(self, request, pk):
"""获取当一数据"""
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book)
return Response(ser.data)
def update(self, request, pk):
"""更新数据"""
# 1. 获取前端数据
data = request.data
# 2. 验证数据
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
ser = BookSerializer(book, data=data)
ser.is_valid()
# 3. 更新数据
ser.save()
# 4. 返回结果
return Response(ser.data)
def destroy(self, request, pk):
"""删除单一数据"""
try:
book = BookInfo.objects.get(id=pk)
except:
return Response({'error': '错误信息'}, status=400)
book.is_delete = True
book.save()
# 返回结果
return Response({})
路由配置urls.py
urlpatterns = [
url(r'^books_drf/$', genericviewset_view.Books.as_view({'get': 'list', 'post': 'create'})),
url(r'^books_drf/(?P<pk>\d+)/$', genericviewset_view.BookDRFView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
视图集 - 拓展类视图ModelViewSet
继承自GenericAPIVIew
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
from rest_framework.viewsets import ModelViewSet
from books.models import BookInfo
from book_drf.serializer import BookSerializer
class Books(ModelViewSet):
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
路由匹配urls.py
urlpatterns = [
url(r'^books_drf/$', modelview_set.Books.as_view({'get': 'list', 'post': 'create'})),
url(r'^books_drf/(?P<pk>\d+)/$', modelview_set.Books.as_view({'put': 'update', 'get': 'retrieve', 'delete': 'destroy'})),
]
源码分析:
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
由于ModelViewSet继承自mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin, mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet。因此会根据请求方法,根据不同场景适配不同处理方法。
补充:视图集中定义附加action动作
在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。
添加自定义动作需要使用rest_framework.decorators.action
装饰器。
以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。
action装饰器可以接收两个参数:
- methods: 该action支持的请求方式,列表传递
- detail: 表示是action中要处理的是否是视图资源的对象(即是否通过url路径获取主键)
- True 表示使用通过URL获取的主键对应的数据对象
- False 表示不使用URL获取主键
完整视图views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from books.models import BookInfo
from book_drf.serializer import BookSerializer
class Books(ModelViewSet):
queryset = BookInfo.objects.all() # 指定当前类视图使用的查询集数据
serializer_class = BookSerializer # 指定当前类视图使用的序列化器
# detail为False 表示不需要处理具体的BookInfo对象
@action(methods=['get'], detail=False)
def latest(self, request):
"""
返回最新的图书信息
"""
book = BookInfo.objects.latest('id')
serializer = self.get_serializer(book)
return Response(serializer.data)
# detail为True,表示要处理具体与pk主键对应的BookInfo对象
@action(methods=['put'], detail=True)
def read(self, request, pk):
"""
修改图书的阅读量数据
"""
book = self.get_object()
book.bread = request.data.get('bread')
book.save()
serializer = self.get_serializer(book)
return Response(serializer.data)
匹配路由urls.py
urlpatterns = [
url(r'^books_drf/latest/$', modelview_set.Books.as_view({'get': 'latest'})),
url(r'^books_drf/(?P<pk>\d+)/read/$', modelview_set.Books.as_view({'put': 'read'})),
]