我有两个相关的模型,如下所示:
class Enterprise(models.Model):
id = models.AutoField(primary_key=True)
subsystem_id = models.IntegerField()
name = models.CharField(max_length=255, unique=True)
modif_date = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Project(models.Model):
id = models.AutoField(primary_key=True)
subsystem_id = models.IntegerField()
name = models.CharField(max_length=255)
modif_date = models.DateTimeField(auto_now=True)
enterprise = models.ForeignKey('Enterprise'
on_delete = CASCADE)
active = models.BooleanField(default=True)
在我看来,需要获得所有活跃的企业并列出它们。我是这样做的:
enterprise_list = Enterprise.objects.annotate(project_count=Count('project')).filter(
Q(active=True) | Q(subsystem_id=-1), project_count__gt=0
)
serializer = EnterpriseSerializer(enterprise_list, many=True)
然后,我的序列化程序正在显示带有一些附加查询的项目列表:
class EnterpriseSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=255, required=False)
project_list = serializers.SerializerMethodField()
def get_project_list(self, enterprise):
project_list = Project.objects.filter(Q(active=True) | Q(subsystem_id=-1),
enterprise=enterprise)
serializer = ProjectSerializer(project_list, many=True)
return serializer.data
class Meta:
model = Enterprise
fields = ('id', 'name', 'project_list')
此代码工作正常,但它有非常严重的问题 - 性能。 Enterprise的第一个查询返回~1500对象的列表。然后,对于每个对象,序列化程序执行单个查询以获取项目的其他数据,从而产生~1500个查询。
我已尝试过prefetch_related
和select_related
,但要么我做错了,要么我的情况不起作用。
另一方面,我可以先获得项目清单。这可以消除我的计数注释。但我应该按企业分组,但据我所知,MySQL的Django ORM并不支持这样的操作。我不认为在python中解析数据并将其传递给序列化器,因为dict是个好主意。
你能给我一些如何限制查询的提示吗?也许prefetch/select_related
对我的情况有帮助,但如何在这里正确使用它们?我正在使用MySQL数据库。
答案 0 :(得分:1)
您可以通过以下方式使用prefetch_related
:
from django.db.models import Prefetch
enterprise_list = Enterprise.objects.annotate(project_count=Count('project')).filter(
Q(active=True) | Q(subsystem_id=-1),
project_count__gt=0).prefetch_related(
Prefetch('project_set',
queryset=Project.objects.filter(Q(active=True) | Q(subsystem_id=-1)),
to_attr='projects'
)
)
serializer = EnterpriseSerializer(enterprise_list, many=True)
在serializer.py
中class EnterpriseSerializer(serializers.ModelSerializer):
...
def get_project_list(self, enterprise):
project_list = enterprise.projects
serializer = ProjectSerializer(project_list, many=True)
return serializer.data