Dom*_*och 4 django polymorphism django-models django-rest-framework
我有一种情况,我的模型有外键关系:
# models.py
class Child(models.Model):
parent = models.ForeignKey(Parent,)
class Parent(models.Model):
pass
Run Code Online (Sandbox Code Playgroud)
和我的序列化器:
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
queryset = Child.objects.filter(parent=parent).select_related('parent')
serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
Run Code Online (Sandbox Code Playgroud)
当我在N个父母的视图中调用Parent时,Django在抓取子节点时在序列化器内进行N次数据库调用.有没有办法让所有的孩子为所有家长最小化数据库呼叫的数量?
我试过这个,但它似乎没有解决我的问题:
class ParentList(generics.ListAPIView):
def get_queryset(self):
queryset = Parent.objects.prefetch_related('child')
return queryset
serializer_class = ParentSerializer
permission_classes = (permissions.IsAuthenticated,)
Run Code Online (Sandbox Code Playgroud)
编辑
我已经更新了下面的代码以反映Alex的反馈....它解决了一个嵌套关系的N + 1.
# serializer.py
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
# The all() call should hit the cache
serialized_data = ChildSerializer(parent.child.all(), many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
# views.py
class ParentList(generics.ListAPIView):
def get_queryset(self):
children = Prefetch('child', queryset=Child.objects.select_related('parent'))
queryset = Parent.objects.prefetch_related(children)
return queryset
serializer_class = ParentSerializer
permission_classes = (permissions.IsAuthenticated,)
Run Code Online (Sandbox Code Playgroud)
现在让我们说我还有一个模型,这是一个孙子:
# models.py
class GrandChild(models.Model):
parent = models.ForeignKey(Child,)
class Child(models.Model):
parent = models.ForeignKey(Parent,)
class Parent(models.Model):
pass
Run Code Online (Sandbox Code Playgroud)
如果我将以下内容放入我views.py的父母queryset:
queryset = Parent.objects.prefetch_related(children, 'children__grandchildren')
它看起来并不像那些孙子孙女被带入ChildSerializer,因此,我再次运行另一个N + 1问题.对这个有什么想法吗?
编辑2
也许这会提供清晰度......也许我仍然遇到N + 1数据库调用的原因,是因为我的孩子和孙子类都是多态的....即
# models.py
class GrandChild(PolymorphicModel):
child = models.ForeignKey(Child,)
class GrandSon(GrandChild):
pass
class GrandDaughter(GrandChild):
pass
class Child(PolymorphicModel):
parent = models.ForeignKey(Parent,)
class Son(Child):
pass
class Daughter(Child):
pass
class Parent(models.Model):
pass
Run Code Online (Sandbox Code Playgroud)
我的序列化器看起来更像是这样的:
# serializer.py
class ChildSerializer(serializer.ModelSerializer):
grandchild = serializers.SerializerMethodField('get_children_ordered')
def to_representation(self, value):
if isinstance(value, Son):
return SonSerializer(value, context=self.context).to_representation(value)
if isinstance(value, Daughter):
return DaughterSerializer(value, context=self.context).to_representation(value)
class Meta:
model = Child
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
queryset = Child.objects.filter(parent=parent).select_related('parent')
serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
Run Code Online (Sandbox Code Playgroud)
再加上Grandaughter,Grandson,我会以代码方式为您提供详细信息,但我认为您可以了解相关信息.
当我为ParentList运行我的视图,并且我监视数据库查询时,我得到的内容就是1000个查询,只有少数父母.
如果我在django shell中运行相同的代码,我可以在不超过25个查询的情况下完成相同的查询.我怀疑它可能与我正在使用django-polymorphic库的事实有关?原因在于,除了每个Son/Daughter,Grandson/Granddaughter表之外,还有一个Child和GrandChild数据库表,共有6个表.跨越这些对象.所以我的直觉告诉我,我错过了那些多态表.
或许对我的daata模型有一个更优雅的解决方案?
据我所知,嵌套序列化程序可以访问预取关系,只需确保不修改查询集(即使用all()):
class ParentSerializer(serializer.ModelSerializer):
child = serializers.SerializerMethodField('get_children_ordered')
def get_children_ordered(self, parent):
# The all() call should hit the cache
serialized_data = ChildSerializer(parent.child.all(), many=True, read_only=True, context=self.context)
return serialized_data.data
class Meta:
model = Parent
class ParentList(generics.ListAPIView):
def get_queryset(self):
children = Prefetch('child', queryset=Child.objects.select_related('parent'))
queryset = Parent.objects.prefetch_related(children)
return queryset
serializer_class = ParentSerializer
permission_classes = (permissions.IsAuthenticated,)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2459 次 |
| 最近记录: |