加速序列化程式查詢
假設我們的模型 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)