Django REST framework视图类深度解析与ModelViewSet实战
本文深入解析Django REST framework的视图机制,通过手动实现增删改查功能对比内置视图类的优势。详细讲解ModelViewSet的继承结构、Mixin类的作用及请求方法映射,展示如何利用视图组件简化代码并优化接口逻辑,帮助开发者掌握DRF核心视图用法。
前言
在掌握REST framework封装的视图类之后,我对Python面向对象编程的理解更加深入。
Django REST framework框架内置的视图类充分运用了面向对象封装与继承的特性,提升了开发效率。
接下来,我们将尝试手动实现一个类似DRF内置视图类的功能模块。
目标是实现图书出版社数据的增、删、改、查操作,其中查询功能需区分查询所有出版社和查询特定出版社两种场景。
首先设计简略的数据模型,代码位于models.py文件中:
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=16)
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=16)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=32)
CHOICES = ((1, 'Python'), (2, 'Go'), (3, 'Linux'))
category = models.IntegerField(choices=CHOICES)
pub_date = models.DateField()
publisher = models.ForeignKey(to='Publisher', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.title
接着配置路由url:
我们需要将使用主键pk与不使用pk的路由业务进行明确区分。
from django.contrib import admin
from django.urls import path, re_path
from bms import views
urlpatterns = [
path('admin/', admin.site.urls),
# 查所有对象,与添加对象
re_path(r'publishers/$', views.PublisherView.as_view()),
# 带pk查询具体某一条数据
re_path(r'publishers/(?P<pk>\d+)/$', views.PublisherDetailView.as_view()), # 出版社详情
]
随后定义序列化类,代码位于自创建的serializers.py文件中:
此处省略了新增时需重写的create方法和更新时需重写的update方法的具体实现。
from bms import models
from rest_framework import serializers
class PublisherModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publisher
fields = "__all__"
class AuthorModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = "__all__"
最后是视图views.py的实现代码:
from bms import models
from rest_framework.views import APIView
from rest_framework.response import Response
from bms.serializers import PublisherModelSerializer
##################### 面向对象,手动实现REST framework视图功能##################
class GenericView(APIView):
'''公用类'''
queryset = None
serializer_class = None
def get_queryset(self):
# 让每一次请求来的时候都现查一次数据
print('GeneriView------',self)
return self.queryset.all()
def get_object(self, request, pk):
# 获取具体queryset
return self.get_queryset().filter(pk=pk)
class ListMixin(object):
# mixi.n 混合类,不能单独使用,利用python支持多继承
def get(self, request):
print('ListMixin------------', self)
queryset = self.get_queryset()
ser_obj = self.serializer_class(queryset, many=True)
return Response(ser_obj.data)
class CreateMixin(object):
def post(self, request):
ser_obj = self.serializer_class(data=request.data)
if ser_obj.is_valid():
ser_obj.save()
return Response("ok")
else:
return Response(ser_obj.errors)
class RetrieveMixin(object):
""" 获取具体某一条记录"""
def retrieve(self, request, pk):
'''将此get方法与ListMixin中的get方法区分'''
obj = self.get_object(request, pk).first()
if obj:
ser_obj = self.serializer_class(obj)
return Response(ser_obj.data)
else:
return Response("无效的id")
class UpdateMixin(object):
def put(self, request, pk):
obj = self.get_object(request, pk).first()
if obj:
ser_obj = self.serializer_class(instance=obj, data=request.data, partial=True)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
else:
return Response(ser_obj.errors)
else:
return Response("无效的id")
class DestroyMixin(object):
def delete(self, request, pk):
obj = self.get_object(request, pk)
if obj:
obj.delete()
return Response("删除成功")
else:
return Response("无效的id")
class RetrieveView(GenericView, RetrieveMixin):
'''因两个get方法相冲图,在此曲线访问查询具体对象的get方法'''
def get(self, request, pk):
return self.retrieve(request, pk)
# 出版社
class PublisherView(GenericView, ListMixin, CreateMixin):
'''查所有出版社,增加出版社'''
# 只用写配置项
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
class PublisherDetailView(RetrieveView, UpdateMixin, DestroyMixin):
'''查询具体某一出版社,编辑,删除'''
queryset = models.Publisher.objects.all()
serializer_class = PublisherModelSerializer
通过上述方式实现了基础的增删改查功能,且采用对象封装后,若需添加其他表的查询,仅需编写约6行代码即可实现。
例如:实现作者数据的增删改查功能:
# 作者 class AuthorListView(ListCreateAPIView): queryset = models.Author.objects.all() serializer_class = AuthorModelSerializer class AuthorDetailView(RetrieveUpdateDestroyAPIView): queryset = models.Author.objects.all() serializer_class = AuthorModelSerializer
利用面向对象的封装与继承特性,极大地简化了代码结构,有效减少了代码冗余。
然而,我们手动实现的功能尚不够全面和严谨,Django REST framework提供了封装更完善的内置视图类ModelViewSet。
Django REST framework视图组件
视图组件的主要作用是优化接口逻辑的处理流程。
首先我们来查看ModelViewSet的具体实现:

该视图类继承了5个混合类(Mixin)和一个公共基类。
mixins.py中定义了那五个类,分别封装了增、删、改、查(列表与详情)5个方法,以及其他严谨的功能方法,其结构与上述手动实现类似。
使用这个视图类更加简洁,处理一张表的数据只需定义一个类。

from rest_framework.viewsets import ModelViewSet
class AuthorViewSet(ModelViewSet):
"""
内部封装了这五个方法
list()
create()
retrieve()
update()
destroy()
"""
queryset = models.Author.objects.all()
serializer_class = AuthorModelSerializer
需要注意的是,内置类中封装的方法名与HTTP请求方式名并不完全一致。
list() 方法对应查询所有对象的get请求。
create() 方法对应添加数据的post请求。
retrieve() 方法对应查询具体对象的get请求。
update() 方法对应更新数据的put请求。
destroy() 方法对应删除数据的delete请求。
因此,在url配置中需要设置actions参数,使请求方式与视图方法一一对应。
urlpatterns = [
path('admin/', admin.site.urls),
# 查所有对象,与添加对象
re_path(r'publishers/$', views.PublisherView.as_view()),
# 带pk查询具体某一条数据
re_path(r'publishers/(?P<pk>\d+)/$', views.PublisherDetailView.as_view()), # 出版社详情
re_path(r'authors/$', views.AuthorViewSet.as_view(actions={'get': 'list', 'post': 'create'})), # 作者列表
re_path(r'authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view(
actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})
), # 作者详情
]
此外,REST framework还封装了路由类,关于authors的路由配置还可以采用以下方式编写:
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('authors', views.AuthorViewSet)
urlpatterns += router.urls
不过这种写法可能导致业务关系不够清晰,因此在实际开发中较少使用。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













