Django REST framework视图的用法


Posted in Python onJanuary 16, 2019

前言

在了解了REST farmwork封装的视图类之后,我对python的面向对象有了更深刻的理解。

Django RESR 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

Django REST framework视图的用法

就是继承了5个混合类和一个公共类。

mixins.py中就是那五个类,封装了增删改查查 5个方法,还有其他严谨功能的方法,结构与上面实现的类似

而使用这个视图类就更简单了,一张表只需要一个类

Django REST framework视图的用法

from rest_framework.viewsets import ModelViewSet
class AuthorViewSet(ModelViewSet):
  """
    内部封装了这五个方法
    list()
    create()
    retrieve()
    update()
    destroy()

  """
  queryset = models.Author.objects.all()
  serializer_class = AuthorModelSerializer

因内置类中封装的方法与请求方式的名并不一样

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

不过这样写路由,业务关系不清晰,一般用的少。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
跟老齐学Python之正规地说一句话
Sep 28 Python
简单介绍Python的Django框架的dj-scaffold项目
May 30 Python
Python批量创建迅雷任务及创建多个文件
Feb 13 Python
python生成器表达式和列表解析
Mar 10 Python
Python 读写文件和file对象的方法(推荐)
Sep 12 Python
解决python matplotlib imshow无法显示的问题
May 24 Python
PyCharm的设置方法和第一个Python程序的建立
Jan 16 Python
Python tensorflow实现mnist手写数字识别示例【非卷积与卷积实现】
Dec 19 Python
Python使用Chrome插件实现爬虫过程图解
Jun 09 Python
python爬取网易云音乐热歌榜实例代码
Aug 07 Python
Python爬虫模拟登陆哔哩哔哩(bilibili)并突破点选验证码功能
Dec 21 Python
python中PyQuery库用法分享
Jan 15 Python
Pycharm+Scrapy安装并且初始化项目的方法
Jan 15 #Python
PyCharm 设置SciView工具窗口的方法
Jan 15 #Python
Python设计模式之抽象工厂模式原理与用法详解
Jan 15 #Python
用Pycharm实现鼠标滚轮控制字体大小的方法
Jan 15 #Python
解决在pycharm中显示额外的 figure 窗口问题
Jan 15 #Python
python调用opencv实现猫脸检测功能
Jan 15 #Python
python可视化实现代码
Jan 15 #Python
You might like
PHP+FastCGI+Nginx配置PHP运行环境
2014/08/07 PHP
PHP改进计算字符串相似度的函数similar_text()、levenshtein()
2014/10/27 PHP
详解PHP中的状态模式编程
2015/08/11 PHP
PHP实现的激活用户注册验证邮箱功能示例
2017/06/06 PHP
PHP使用反向Ajax技术实现在线客服系统详解
2019/07/01 PHP
阿里对象存储OSS在laravel框架中的使用方法
2019/10/13 PHP
JQuery入门——用one()方法绑定事件处理函数(仅触发一次)
2013/02/05 Javascript
Bootstrap学习笔记之css组件(3)
2016/06/07 Javascript
js实现密码强度检验
2017/01/15 Javascript
socket.io学习教程之基础介绍(一)
2017/04/29 Javascript
基于node.js之调试器详解
2017/08/22 Javascript
为输入框加入数字js校验代码分享
2017/11/02 Javascript
jquery 输入框查找关键字并提亮颜色的实例代码
2018/01/23 jQuery
vue利用axios来完成数据的交互
2018/03/23 Javascript
JavaScript实现计算圆周率到小数点后100位的方法示例
2018/05/08 Javascript
socket io与vue-cli的结合使用的示例代码
2018/11/01 Javascript
js canvas实现画图、滤镜效果
2018/11/27 Javascript
js如何获取图片url的Blob值并预览示例代码
2019/03/07 Javascript
Vue中使用Lodop插件实现打印功能的简单方法
2019/12/19 Javascript
python执行get提交的方法
2015/04/29 Python
tensorflow 加载部分变量的实例讲解
2018/07/27 Python
Python Unittest根据不同测试环境跳过用例的方法
2018/12/16 Python
在Qt5和PyQt5中设置支持高分辨率屏幕自适应的方法
2019/06/18 Python
Python模块相关知识点小结
2020/03/09 Python
详解基于Jupyter notebooks采用sklearn库实现多元回归方程编程
2020/03/25 Python
python上传时包含boundary时的解决方法
2020/04/08 Python
Python配置pip国内镜像源的实现
2020/08/20 Python
Keds官方网站:购买帆布运动鞋和经典皮鞋
2016/11/12 全球购物
医药代表个人的求职信分享
2013/12/08 职场文书
表扬信格式
2014/01/12 职场文书
服装设计师职业生涯规划范文
2014/02/28 职场文书
道路施工安全责任书
2014/07/24 职场文书
党员教师四风问题整改措施思想汇报
2014/10/08 职场文书
医生个人年终总结
2015/02/28 职场文书
尊师重教主题班会
2015/08/14 职场文书
用Python仅20行代码编写一个简单的端口扫描器
2022/04/08 Python