上一节描述了如何根据model快速生成API,这一节展开讲讲在DRF
的orm2rest
中各元素的作用。
各元素作用
model
定义数据库模型,会根据此模型生成数据库表,如果修改模型会生成数据库DDL
语句filter
过滤器,自动生成的API提供过滤参数serializer
序列化,用于处理返回数据,可自定义添加返回内容viewset
用来提供API接口,DRF
支持继承后自动生成,也可自定义接口处理内容和增加接口
灵活使用这几个可以自定义接口不同阶段的内容
model
model
定义数据库模型,会根据此模型生成数据库表,如果修改模型会生成数据库DDL
语句。
在这篇文章中的django
节有提到过一个model
如下:
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
我们可以定义不同的字段类型,django
已经实现了所有的数据字段类型,更多字段含义见tutorial02/#creating-models
常用的字段参考如下:
title = models.CharField(max_length=100, blank=True, null=True, verbose_name='标题')
weight = models.FloatField(verbose_name='权重', default=1)
is_deleted = models.IntegerField(verbose_name='软删除/启用', default=0)
create_time = models.DateTimeField(blank=True, null=True, verbose_name='创建时间', auto_now_add=True)
update_time = models.DateTimeField(blank=True, null=True, verbose_name='更新时间', auto_now=True)
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True,
verbose_name='父子关系,根pid为0', related_name='child_menus')
blank
是否可以空白,null
是否可以为NULL
verbose_name
注释- 时间类型的
DateTimeField
可以自动补充时间,auto_now_add=True
是创建时自动赋值,auto_now=True
是更新时刷新 ForeignKey
外键
拓展:可以使用如下语法来指定表名
class Question(models.Model):
# ....
class Meta:
db_table = '表名'
filter
filter
过滤器,自动生成的API提供过滤参数
from django_filters.rest_framework import FilterSet
class TestFilter(FilterSet):
class Meta:
model = Test
fields = '__all__'
模糊查询、in
过滤器都是精准匹配的,如果想要一次性查询同一个参数不同数值可以
class TestFilter(FilterSet):
class Meta:
model = Test
fields = {
'id': ['exact', 'in'],
'xxx': ['exact', 'in'],
}
exact
保留原始字段in
同一个参数不同数值,接入会增加一个xxx__in
参数,值填1,2,3
用逗号隔开contains
大小写敏感的模糊匹配,icontains
大小写不敏感- 用这种方式过滤参数只会显示
fields
有的,如果需要请补齐全部
加入字段可以有不同的表现,如下可以自定义过滤方法,过滤内容
class TestFilter(FilterSet):
f = filters.BooleanFilter(method="fFilter")
class Meta:
model = Test
fields = {
# ...
def fFilter(self, queryset, name, value):
if value:
return queryset.filter(xx=xx)
else:
return queryset
如果model
里配置了外键,可以使用外键字段关联查询
user_name = filters.CharFilter(field_name="user_id__username")
user_name__icontains = filters.CharFilter(field_name="user_id__username", lookup_expr="icontains")
- 如上使用外键
user
表中的username
查询 - 不需要在
fields
字段里做任何配置
serializer
serializer
序列化,用于处理返回数据,可自定义添加返回内容
from rest_framework import serializers
class TestSerializer(serializers.ModelSerializer):
class Meta:
#与test表对应
model = Test
#取全部字段
fields = '__all__'
增加一个自定义范围字段
class SlaSerializer(serializers.ModelSerializer):
data = serializers.SerializerMethodField()
class Meta:
#....
def get_data(self, obj):
data = {}
if obj.xxx is None:
return data
xxx = xxx.objects.filter(xxx=xxx,xxx_range=(x,x)).first()
x = XxxxSerializer(xxx, many=True).data
data['xx']=x.x
return data
- 如上
obj
是查询到的单条记录,可以用这条记录里的任意字段 - 组合任意格式内容作为返回
在序列化方法里还能取到查询参数,比如你想根据查询参数改变范围内容的话用得上
if 'request' not in self.context:
return data
params = self.context['request'].query_params
if 'begin_time' not in params or 'end_time' not in params:
return data
参数验证
可以在serializer
类中进行参数验证
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ["url", "username", "email", "is_staff"]
def validate_username(self, username: str) -> str:
if len(username) < 10:
raise serializers.ValidationError(
"Username must be at least 10 characters long.",
)
return username
如果是反复复用的验证方法也可以直接写在model
类中
script_type = models.CharField(max_length=100, blank=True, null=True, verbose_name='脚本类型',
validators=[validate_script_type])
格式
def validate_script_type(value):
if value not in ['python', 'shell']:
raise ValidationError(_('%(value)s is not in "python" or "shell"'), params={'value': value}, )
viewset
viewset
用来提供API接口,DRF
支持继承后自动生成,也可自定义接口处理内容和增加接口
from rest_framework import viewsets
class TestViewSet(viewsets.ModelViewSet):
filter_class = TestFilter
queryset = Test.objects.all()
serializer_class = TestSerializer
自定义API、重写API
1.create(post请求)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
2.list (get请求)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
3.update (patch)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
4.destroy(delete请求)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
5.retrieve(单个请求http://xxx/xxx/6/
根据id
来查询)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
当然也可以随意定义方法,定义一个方法自动生成一个API
事前操作
class XxxViewSet(viewsets.ModelViewSet):
filter_class = XxxFilter
queryset = Xxx.objects.all().order_by("id")
serializer_class = XxxSerializer
authentication_classes = []
permission_classes = []
- 如上可以事前排序等对查询结果做任何操作
- 定义序列化类
- 定义身份校验
- 定义权限
我就不展开讲了
高频操作
执行查询直接看官网 https://docs.djangoproject.com/zh-hans/4.0/topics/db/queries/#querying-jsonfield
小结
通过这一小节更清楚的体会了DRF
的各个阶段可以自定义哪些内容,相信用起来就更顺手了
更多知识:身份校验,限流,未来可能会更新
评论