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 所返回的
来源: https://www.cnblogs.com/luozx207/p/10491920.html