DRF(Django REST framework)是一个高度封装的框架,这导致想完成一件事情可以通过重写父类函数的方式从DRF的各个层次来写,都能够实现目的。

比如写视图函数,可以用继承APIView的方式或者继承Viewsets的方式,甚至直接写视图函数

但是想要更加干净简洁的代码,还是需要找到实现的最佳方式

以下是我的一些个人总结,欢迎讨论

models.py

1.PositiveSmallIntegerField

  • Positive对应unsigned
  • Small对应smallint(5)
  • 对于一些数据量较小的系统可以使用这个Field作为id

2、字段定义中verbose_name定义的是django自带接口ui的字段说明,help_text定义的是swagger的字段说明

3、tag = models.ForeignKey(Tag, related_name="project_tag")

  • 定义一个外键会在数据库中生成一个名为tag_id的字段
  • 但是在模型实例中,tag是Tag模型的实例
  • 也就是说,Django的ORM会把tag.id=tag_id的Tag模型实例取出来放到tag字段

4、user = models.ForeignKey(User, unique=True)

  • 相当于user = models.OneToOneField(User)
  • 外键 on_delete = models.CASCADE 级联删除是默认的选项

5、ImageField和FileField实际上是CharFields

serializers.py

1、serializers中对字段做出的限制只会影响前端传到后端的数据,而不会影响后端传到前端的数据

例如

class MySerializer(serializers.ModelSerializer):
TYPE = (
# (0, "级别一"), #在model中这行没有注释掉
(1, "级别二"),
(2, "级别三")
)
# 这样可以限制前端不能传my_type=0的数据,但是my_type=0的数据可以在前端接收到
my_type = ChoiceField(choices=TYPE,required=True)

2、一般来说,update和create的操作都会在serializers中实现

  • 很多刚开始接触DRF的同学会习惯在view中写update和create,其实,在serializers中实现是一种更好的方法,

    因为,这样你的代码不用绕来绕去。不用费劲获取serializer的值再费劲存到serializer里,直接在serializer中实现就行了。

    别看create和update函数的源码那么长,其实不用管它们,整个重写就好了

  • update与create函数框架

def create(self, validated_data):
...
return instance def update(self, instance, validated_data):
...
return instance

validated_data是经过验证的前端数据,instance是用id获取的对应数据库数据的模型实例

它们都要返回一个模型实例,作为返回前端的数据

  • update和create方法由serializer.save()函数调用
  • 在serializer中self.context["request"]相当于view中的self.request
  • 在Model.objects的创建或筛选中,可以直接拿一个模型实例赋值给外键字段或相比较,比如
Model1.objects.create(user=self.context["request"].user,
foreign_key=foreign_key_instance)
  • 如果要用一个已有的模型实例的数据创建一条新数据,我曾用过一个不优雅的写法
for key in update_data:
setattr(instance, key, update_data[key])
# 把对象转为字典,作为新建数据的参数
dic = instance.__dict__
del dic['id']
del dic['_state']
new_instance = Model1.objects.create(**dic)

先把更新后的实例对象转为字典,再删掉id等在数据表插入新数据时不该传的数据,再将字典作为objects.create的参数

其实有一个更巧妙的方法

instance.id = None
for attr, value in update_data.items():
setattr(instance, attr, value)
instance.save()

instance.save()之后,instance将会变成新插入数据的模型实例

  • 某些情况需要父类函数的写法,不需要复制代码,用super就可以了
super(Model1Serializer, self).update(instance, validated_data)

views.py

1、perform_create中的serializer.save()语句可以带参数,比如

user_id = self.request.user.id
serializer.save(user=User.objects.get(id=user_id))

实现从request中获取user的值,而不是从表单

2、尽量使用objects.filter而不是get

  • filter返回一个数组,get返回一个数据库实例
  • 如果get()中的过滤条件没有匹配出数据,get().delete()会报错,filter则会取出一个空数组,不会报错

3、过滤器的使用

  • 应避免在get_queryset()中使用复杂的逻辑,比如
def get_queryset(self):
key_1 = self.request.key1
key_2 = self.request.key2
my_type = self.request.query_params.get('type', None)
if my_type == 1:
return Model.objects.filter(foreign_key_1=key_1)
elif my_type == 2:
return Model.objects.filter(foreign_key_2=key_2)
# 默认情况,返回所有
return Model.objects.all()

其实这就是一个根据查询参数过滤的过程,完全可以使用过滤器实现,这样在Django自带ui中也会有过滤器的说明

  • 要使用过滤器,首先安装库

    pip install django-filter

python2要特别指定django-filter==1.1

  • 然后在settings的INSTALLED_APPS中加上django_filters
  • 新建一个名为filters.py的文件,定义一个过滤器
class MyFilter(django_filters.rest_framework.FilterSet):
MY_TYPE = (
(1, "类别一"),
(2, "类别二")
) type = django_filters.ChoiceFilter(help_text="类型",
label="类型",
choices=MY_TYPE,
method="type_filter"
) def type_filter(self,queryset,name,value):
key_1 = self.request.key1
key_2 = self.request.key2
if value == 1:
return queryset.filter(foreign_key_1=key_1)
elif value == 2:
return queryset.filter(foreign_key_2=key_2) class Meta:
model = Tag
fields = ['type']
  • 在viewset中加上
filter_backends = (DjangoFilterBackend, )
filter_class = MyFilter

而get_queryset函数只需要一句return Model.objects.all()就好

注意type_filter的queryset就是get_queryset所返回的

如何更优雅地写Django REST framework的更多相关文章

  1. JavaScript 复杂判断的更优雅写法

    我们编写js代码时经常遇到复杂逻辑判断的情况,通常大家可以用if/else或者switch来实现多个条件判断,但这样会有个问题,随着逻辑复杂度的增加,代码中的if/else/switch会变得越来越臃 ...

  2. JavaScript复杂判断的更优雅写法

    摘要: 写代码是一门艺术. 原文:JavaScript 复杂判断的更优雅写法 作者:Think. 公众号:大转转fe Fundebug经授权转载,版权归原作者所有. 前提 我们编写js代码时经常遇到复 ...

  3. js中如何优雅的写if判断

    我们编写js代码时经常遇到复杂逻辑判断的情况,通常大家可以用if/else或者switch来实现多个条件判断,但这样会有个问题,随着逻辑复杂度的增加,代码中的if/else/switch会变得越来越臃 ...

  4. 【转】转自微信公众号 JavaScript 复杂判断的更优雅写法

    与微信公众号看到一篇js复杂判断的文章,对我启发很大,故转到博客园以供后期不断学习并应用于项目.原文地址:https://mp.weixin.qq.com/s/ClFDRj4MnAxv1dJ5VWKS ...

  5. CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅

    首页   登录注册         CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅 阅读 8113 收藏 927 2017-09-26 原文链接:github.com 腾讯云容器服务CSS,立 ...

  6. 9条消除if...else的锦囊妙计,助你写出更优雅的代码

    前言 最近在做代码重构,发现了很多代码的烂味道.其他的不多说,今天主要说说那些又臭又长的if...else要如何重构. 在介绍更更优雅的编程之前,让我们一起回顾一下,不好的if...else代码 一. ...

  7. python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...

  8. Django REST Framework 学习笔记

    前言: 基于一些不错的RESTful开发组件,可以快速的开发出不错的RESTful API,但如果不了解开发规范的.健壮的RESTful API的基本面,即便优秀的RESTful开发组件摆在面前,也无 ...

  9. 如何优雅的写一篇安利文-以Sugar ORM为例

    前言 我最近喜欢把写的十分优美的技术文章叫做安利文.首先,文章必须是原创而非软广:其次,阅读之后不仅能快速吸纳技术要点并入门开发,还能感同身受的体会作者热情洋溢的赞美和急于分享心得体验的心情,让人感觉 ...

随机推荐

  1. 面试问题总结二(技术能力-PHP)----Ⅲ

    42.什么是单点登录? 答:单点登录 SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信 ...

  2. 一些基于jQuery开发的控件

    基于jQuery开发,非常简单的水平方向折叠控件.主页:http://letmehaveblog.blogspot.com/2007/10/haccordion-simple-horizontal-a ...

  3. Day22-Django之Form组件验证

    1. Django里面的Form专门用来做验证. 用Form创建一个类,把用户发来的数据放到request.POST里面发给这个类,这个类会帮忙做验证. 返回3个结果:是否验证成功了,所有的正确信息, ...

  4. 【刷题】BZOJ 4998 星球联盟

    Description 在遥远的S星系中一共有N个星球,编号为1-N.其中的一些星球决定组成联盟,以方便相互间的交流.但是,组成联盟的首要条件就是交通条件.初始时,在这N个星球间有M条太空隧道.每条太 ...

  5. UltraISO制作U盘启动盘

    第一步:导入镜像文件 文件->打开 第二步: 启动->写入硬盘映像 隐藏启动分区选择“无” 然后等待即可.

  6. 洛谷 P2805 [NOI2009]植物大战僵尸 解题报告

    P2805 [NOI2009] 植物大战僵尸 题目描述 Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plan ...

  7. ActiveMQ反序列化漏洞(CVE-2015-5254)复现

      0x00 漏洞前言 Apache ActiveMQ是美国阿帕奇(Apache)软件基金会所研发的一套开源的消息中间件,它支持Java消息服务,集群,Spring Framework等.Apache ...

  8. SpringBoot 中使用redis以及redisTemplate

    1.首先在pom.xml中添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <art ...

  9. mysql INNER/LEFT/RIGHT JOIN区别

    1.创建table DROP TABLE IF EXISTS `tab_id_index`; CREATE TABLE `tab_id_index` ( `id` ) ', `name` ) DEFA ...

  10. android:shape的使用(+圆角ListView)(转)

    http://dev.10086.cn/cmdn/wiki/index.php?doc-view-6087.html Android中常常使用shape来定义控件的一些显示属性,今天看了一些shape ...