加速序列化程序查询
假设我们的模型 Travel
有很多相关领域:
class Travel(models.Model):
tags = models.ManyToManyField(
Tag,
related_name='travels', )
route_places = models.ManyToManyField(
RoutePlace,
related_name='travels', )
coordinate = models.ForeignKey(
Coordinate,
related_name='travels', )
date_start = models.DateField()
我们想通过视图 ViewSet 在/travels
中构建 CRUD。
这是简单的视图集:
class TravelViewset(viewsets.ModelViewSet):
queryset = Travel.objects.all()
serializer_class = TravelSerializer
这个 ViewSet 的问题是我们的 Travel
模型中有很多相关的字段,所以 Django 会为每个 Travel
实例命中 db。我们可以直接在 queryset
属性中调用 select_related 和 prefetch_related ,但是如果我们想要为 Viewh 的 list
,retrieve
,create
..动作分隔序列化器呢?
所以我们可以将这个逻辑放在一个 mixin 中并继承它:
class QuerySerializerMixin(object):
PREFETCH_FIELDS = [] # Here is for M2M fields
RELATED_FIELDS = [] # Here is for ForeignKeys
@classmethod
def get_related_queries(cls, queryset):
# This method we will use in our ViewSet
# for modify queryset, based on RELATED_FIELDS and PREFETCH_FIELDS
if cls.RELATED_FIELDS:
queryset = queryset.select_related(*cls.RELATED_FIELDS)
if cls.PREFETCH_FIELDS:
queryset = queryset.prefetch_related(*cls.PREFETCH_FIELDS)
return queryset
class TravelListSerializer(QuerySerializerMixin, serializers.ModelSerializer):
PREFETCH_FIELDS = ['tags'']
RELATED_FIELDS = ['coordinate']
# I omit fields and Meta declare for this example
class TravelRetrieveSerializer(QuerySerializerMixin, serializers.ModelSerializer):
PREFETCH_FIELDS = ['tags', 'route_places']
现在用新的序列化器重写我们的 ViewSet
class TravelViewset(viewsets.ModelViewSet):
queryset = Travel.objects.all()
def get_serializer_class():
if self.action == 'retrieve':
return TravelRetrieveSerializer
elif self.action == 'list':
return TravelListSerializer
else:
return SomeDefaultSerializer
def get_queryset(self):
# This method return serializer class
# which we pass in class method of serializer class
# which is also return by get_serializer()
q = super(TravelViewset, self).get_queryset()
serializer = self.get_serializer()
return serializer.get_related_queries(q)