drf 视图家族

前期准备

总路由 urls.py

from django.contib import admin
from django.views import serve
from django.conf import settings urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include('api.urls')),
url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
]

基表:utils/models.py

from django.db import models

class BaseModel(models.Model):
is_delete = models.BooleanField(default=False)
create_time = models.DateTimeField(auto_now_add=True, null=True) class Meta:
# 抽象表, 不会完成数据库迁移
abstract = True

模型层 api/models.py

from django.db import models
from utils.models import BaseModel class Book(BaseModel):
name = models.CharField(max_length=64)
price = models.DecimalField(max_digits=6, decimal_places=2)
img = models.ImageField(upload_to='icon', default='icon/default.png')
publish = models.ForeignKey(to='Publish',
null=True,
related_name='books',
db_constraint=False,
on_delete=models.DO_NOTHING
)
authors = models.ManyToManyField(to='Author',
related_name='authors',
db_constraint=False @property
def publish_info(self):
return {'name': self.publish.name, 'address': self.publish.address} @property
def author_info(self):
author_list = [] for author in self.authors.all():
detail = AuthorDetail.objects.filter(author_id=self.author.id)
author_list.append({
'name': author.name,
'age': author.age,
'mobile': '未知' if not detail else author.detail.mobile
}) return author_list class Meta:
db_table = "books"
verbose_name = '书籍'
verbose_name_plural = verbose_name def __str__(self):
return self.name class Author(BaseModel):
name = models.CharField(max_length=64)
age = models.IntegerField() @property
def mobile(self):
return self.detail.mobile class Meta:
db_table = 'author'
verbose_name = '作者'
verbose_name_plural = verbose_name def __str__(self):
return self.name class AuthorDetail(BaseModel):
mobile = models.CharField(max_length=11)
author = models.OneToOneField(to='Author',
null=True,
related_name='detail',
db_constraint=False,
on_delete=models.CASCADE
)
class Meta:
db_table = 'detail'
verbose_name = '作者详情'
verbose_name_plural = verbose_name def __str__(self):
return f"{self.author.name}的详情" class Publish(BaseModel):
name = models.CharField(max_length=64)
address = models.CharField(max_length=128) class Meta:
db_table = 'publish'
verbose_name = '出版社'
verbose_name_plural = verbose_name def __str__(self):
return self.name

序列化器 api/serializers.py

from rest_framework import serializers
from . import models class BookListSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
for ind, obj in enumerate(instance):
for attr, value in validated_data[ind].items():
if hasattr(obj, attr):
set(obj, attr, value)
obj.save()
return instance class BookV2ModelSerializer(serializers.ModelSerializer):
re_name = serializers.CharField(
min_length=3,
required=True,
write_only=True, # 只参与反序列化
error_messages={
'min_length': '太短了',
'required': '不能为空'
}
) class Meta:
model = models.Book
fields = ('name', 're_name', 'price', 'img', 'publish', 'publish_info', 'authors', 'authors_info')
list_serializer_class = BookListSerializer
extra_kwargs = {
'name':{
'min_length': 3,
'error_messages': {
'min_length': '太短了',
'required': '不能为空'
}
},
# 有默认值的字段会默认required为False,在反序列化中如果不传值不会进行校验,但是如果传值就会进行校验
'publish':{
'required': True,
'write_only': True,
'error_messages':{
'required': '不能为空'
}
},
'authors':{
'required': True,
'write_only': True,
'error_messages':{
'required': '不能为空'
}
},
} # 自定义校验规则
# 局部钩子
def validate_name(self, value):
if 'sb' in value:
raise serializers.ValidationError('书名包含敏感词汇')
return value # 全局钩子
def validate(self, attr):
name = attr.get('name')
re_name = attr.get('re_name')
publish = attr.get('publish')
if name != re_name:
raise serializers.ValidationError(
{'re_name': '两次书名不一致'}
) # 通过逻辑控制联合唯一
if models.Book.objects.filter(name=name, publish=publish):
raise serializers.ValidationError(
{'book': '书籍已存在'}
)
return attr

基本视图(views)

主要就是通过视图类APIView,里面的逻辑都需要自己去实现,需要自己写接口

子路由 api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^books/$', views.BookAPIView.as_view()),
url(r'^books/(?P<pk>.*)/$', views.BookAPIView.as_view()),
]

视图层 api/views.py

from rest_framework import views
from . import models, serializers
from utils.response import APIResponse class BookAPIView(views.APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 单取
if pk:
book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first()
if not pk:
return APIResponse(1, 'pk有误')
book_ser = serializers.BookV2ModelSerializer(book_obj)
return APIResponse(0, 'ok', results=book_ser.data) # 群取
book_obj_list = models.Book.objects.filter(is_delete=False).all()
if not book_obj_list:
return APIResponse(1, '没有数据')
book_ser = serializers.BookV2ModelSerializer(book_obj_list, many=True)
return APIResponse(0, 'ok', results=book_ser.data) # 增加
def post(self, request, *args, **kwargs):
# 把单增也转换为群增
request_data = request.data
if isinstance(request_data, dict):
data = [request_data, ]
elif isinstance(request, list):
data = request_data
else:
return APIView(1, '数据格式有误') book_ser = serializers.BookV2ModelSerializer(data=data, many=True)
if book_ser.is_valid():
book_obj_list = book_ser.save()
results = serializers.BookV2ModelSerializer(book_obj_list, many=True).data
return APIResponse(0, 'ok', results=results)
else:
return APIResponse(1, '添加失败', results=book_ser.errors)

视图工具类(mixins)

  1. RetrieveModelMixin:retrieve方法实现了获取一个对象
  2. ListModelMixin:list方法实现了获取多个对象
  3. CreateModelMixin:create方法实现了增加一个对象
  4. UpdateModelMixin:update方法实现了单整体更新,partial_udate实现了单局部更新
  5. DestroyModelMixin:destory方法实现了单独删除

一般结合generics工具视图使用

工具视图(generics)

GenericAPIView

GenericAPIView,是generics家族的基类,主要帮我们把qureysetserializer_class封装成了属性,提供了以下三种方法:

  • get_qureyset():获取多个对象
  • get_object():获取一个对象
  • get_serializer(*args, **kwargs):获取序列化后的对象

GenericAPIView的子类们

继承了mixins中多个功能类和GenericAPIView基类

类名 实现接口
CreateAPIView 单增(post)
ListAPIView 多取(get)
RetrieveAPIView 单取(get)
DestroyAPIView 单删(delete)
UpdateAPIView 单局部(patch)及整体(put)修改
ListCreateAPIView 多取(get)和多增(post)
RetrieveUpdateAPIView 单取(get),单局部(patch)及整体(put)修改
RetrieveDestroyAPIView 单取(get)和单删(delete)
RetrieveUpdateDestroyAPIView 单取(get),单局部(patch)及整体(put)修改和单删(delete)

子路由 api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
# generics
url(r'^v1/books/$', views.BookGenericAPIView.as_view()),
url(r'^v1/books/(?P<pk>.*)/$', views.BookGenericAPIView.as_view()), # mixins + generics
url(r'^v2/books/$', views.BookMixinsGenericAPIView.as_view()),
url(r'^v2/books/(?P<pk>.*)/$', views.BookMixinsGenericAPIView.as_view()), # 系统整合mixins、generics
url(r'^v3/books/$', views.BookRetrieveUpdateAPIView.as_view()),
url(r'^v3/books/(?P<pk>.*)/$', views.BookRetrieveUpdateAPIView.as_view()),
]

视图层 api/views.py

from rest_framework import generics, mixins
from . import models, serializers
from utils.response import APIResponse # v1 generics - 视图基类
class BookGenericAPIView(generics.GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
book_obj = self.get_object()
book_ser = self.get_serializer(book_obj)
return APIResponse(0, 'ok', results=book_ser.data)
book_query = self.get_queryset()
book_ser = self.get_serializer(book_query, many=True)
return APIResponse(0, 'ok', results=book_ser.data) def post(self, request, *args, **kwargs):
book_ser = self.get_serializer(data=request.data)
book_ser.is_valid(raise_exception=True)
book_obj = book_ser.save()
return APIResponse(0, 'ok', results=self.get_serializer(book_obj).data) # v2 mixins工具集 + generics视图基类
class BookMixinsGenericAPIView(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer
def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
response = self.retrieve(request, *args, **kwargs)
else:
response = self.list(request, *args, **kwargs)
return APIResponse(0, 'ok', results=response.data) def post(self, request, *args, **kwargs):
response = self.create(request, *args, **kwargs)
return APIResponse(0, 'ok', results=response.data) # v3 视图基类子类 - 工具视图类
class BookRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer

视图集(viewsets)

ViewSetMixin:视图集工具,重写了as_view方法, 完成了请求方式到视图类中的方法的映射

例如:.as_view({'get': 'retrieve', 'delete': 'remove_obj'}), 表示当请求方式为get的时候,则会调用retrieve函数,当请求方式为delete的时候,则会调用remove_obj函数

GenericViewSet:与模型类有关的接口视图集 - 可以从mixins那继承功能,也可以自定义功能

ViewSet:与模型类无关或不是标准模型类接口 - 一般都是自定义功能

子路由 api/urls.py

from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^v4/books/$', views.BookGenericViewSet.as_view({
'get': 'list',
'post': 'create'
})),
url(r'^v4/books/(?P<pk>.*)/$', views.BookGenericViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'remove_book'
})),
]

视图层 api/views.py

from rest_framework import mixins, viewsets
from . import models, serializers
from utils.response import APIResponse class BookGenericViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
queryset = models.Book.objects.filter(is_delete=False).order_by('-id')
serializer_class = serializers.BookModelSerializer def remove_book(self, request, *args, **kwargs):
pk = kwargs.get('pk')
try:
book_obj = models.Book.objects.get(is_delete=False, pk=pk)
book_obj.is_delete = True
book_obj.save()
return APIResponse(0, '删除成功')
except:
return APIResponse(1, '删除失败')

最新文章

  1. 学习UFT11.5历程(三)
  2. soapui中文操作手册(六)----创建REST Testing
  3. 161222、Bootstrap table 服务器端分页示例
  4. oracle 查看锁表情况并处理锁表
  5. SQL Server2008 程序设计 汇总 GROUP BY,WITH ROLLUP,WITH CUBE,GROUPING SETS(..)
  6. Mybatis中实现oracle的批量插入、更新
  7. 使用JS进行pc端、手机端判断
  8. Android显示GIF动画完整示例(一)
  9. 基于visual Studio2013解决C语言竞赛题之0704字符串长度
  10. 弹出层 div dialog
  11. 【IOS 开发】Object-C 入门 Xcode 环境具体解释
  12. Webapi帮助文档
  13. 搭建struct环境
  14. bat入门--第一个bat文件
  15. [转帖]Oracle 裁员史:技术人死于重组,卒于云计算
  16. Educational Codeforces Round 23 B. Makes And The Product
  17. BZOJ4735:你的生命已如风中残烛(组合数学)
  18. 20135202闫佳歆--week4 系统调用(上)--学习笔记
  19. API:详解 pandas.read_csv
  20. Java编辑PPT的折线图,与内嵌Excel联动

热门文章

  1. 调试CEF3程序的方法
  2. rn相关文档
  3. HTML基础一-html、CSS
  4. 1. vue 的安装
  5. [KCOJ20170214]又一个背包
  6. Qt常用类——QFrame类与QWidge类
  7. Oracle客户端和服务端菜单区别
  8. 获取当前页面url指定参数值
  9. 详细讲解redis数据结构(内存模型)以及常用命令
  10. Apache的安装部署 2(加密认证 ,网页重写 ,搭建论坛)