Django 子查询中注释内的注释?

Han*_*nny 5 python django django-models django-rest-framework django-annotate

我有一些模型,正在尝试加快列出用户的页面的速度。

问题是我正在利用模型方法来显示一些数据 - 但是当我列出用户时,它会多次访问数据库,最终UserUser导致数百个额外查询(当列表中有数千个对象时,会出现数千个查询) )所以这对性能造成了严重影响。

从那时起我就开始使用annotateand ,prefetch_related这大大减少了查询。我只是有点不知道如何注释。

我有一个模型方法(在Summation模型上),用于获取Evaluation用户的数据摘要,如下所示:

    def evaluations_summary(self):
        evaluations_summary = (
            self.evaluation_set.all()
            .values("evaluation_type__name")
            .annotate(Count("evaluation_type"))
        )
        return evaluations_summary
Run Code Online (Sandbox Code Playgroud)

我试图弄清楚如何注释对象上的特定查询User

因此,这种关系看起来User有多个Summations,但只有一个是“活动的”,这就是我们在列表中显示的那个User。每个Summation都有多个Evaluations- 我们也试图展示其摘要。

这里是代码相关部分的摘要(包括Summation模型方法,它给出了当前正在“工作”以根据需要显示数据的示例) - 我还制作了一个Pastebin 示例以便于查看。

# MODELS 
 
class User(AbstractUser):
    employee_no = models.IntegerField(default=1)
    ...all the other usual attributes...
 
class Summation(CreateUpdateMixin, CreateUpdateUserMixin):
    # CreateUpdateMixin adds 'created_at' & 'updated_at
    # CreateUpdateUserMixin adds 'created_by' & 'updated_by'
    employee = models.ForeignKey(
        User, on_delete=models.PROTECT, related_name="%(class)s_employee"
    )
    report_url = models.CharField(max_length=350, blank=True)
    ...other unimportant attributes...
 
    def evaluations_summary(self):
        evaluations_summary = (
            self.evaluation_set.all()
            .values("evaluation_type__name")
            .annotate(Count("evaluation_type"))
        )
        return evaluations_summary
 
 
class Evaluation(CreateUpdateMixin, CreateUpdateUserMixin):
    summation = models.ForeignKey(Summation, on_delete=models.PROTECT)
    evaluation_type = models.ForeignKey(
        EvaluationType, on_delete=models.PROTECT
    )
    evaluation_level = models.ForeignKey(
        EvaluationLevel, on_delete=models.PROTECT
    )
    evaluation_date = models.DateField(
        auto_now=False, auto_now_add=False, null=True, blank=True
    )
    published = models.BooleanField(default=False)
 
class EvaluationLevel(CreateUpdateMixin):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=50)    
 
class EvaluationType(CreateUpdateMixin):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=50)
    evaluation_levels = models.ManyToManyField(EvaluationLevel)   
 
 
# SERIALIZERS
 
class UserSerializer(serializers.HyperlinkedModelSerializer):
    multiple_locations = serializers.BooleanField()
    multiple_jobs = serializers.BooleanField()
    summation_status_due_date = serializers.DateField()
    summation_employee = SummationSerializer(many=True, read_only=True)
    evaluations_summary = serializers.SerializerMethodField()
 
    class Meta:
        model = User
        fields = [
            "url",
            "id",
            "username",
            "first_name",
            "last_name",
            "full_name",
            "email",
            "is_staff",
            "multiple_locations",
            "multiple_jobs",
            "summation_status_due_date",
            "summation_employee",
            "evaluations_summary",
        ]

     def get_evaluations_summary(self, obj):
        return (
            obj.summation_employee__evaluation_set.all()
            .values("evaluation_type__name")
            .annotate(Count("evaluation_type"))
        )
 
 
# CURRENT ANNOTATIONS
 
    # Subqueries for evaluation_summary
    active_summations = (
        Summation.objects.filter(employee=OuterRef("pk"), locked=False)
    )
    evaluations_set = (
        Evaluation.objects.filter(summation__in=active_summations)
        .order_by()
        .values("evaluation_type__name")
    )
    summary_set = evaluations_set.annotate(Count("evaluation_type"))
 
    # the 'summation_employee__evaluation_set' prefetch does not seem 
    # to make an impact on queries needed
    user_list = (
        User.objects.prefetch_related("summation_employee")
        .prefetch_related("summation_employee__evaluation_set")
        .filter(id__in=all_user_ids)
        # Get the total locations and if > 1, set multiple_locations to True
        .annotate(total_locations=Subquery(total_locations))
        .annotate(
            multiple_locations=Case(
                When(total_locations__gt=1, then=Value(True)),
                default=Value(False),
                output_field=BooleanField(),
            )
        )
        # Get the total jobs and if > 1 set mutiple_jobs to True
        .annotate(total_jobs=Subquery(total_jobs))
        .annotate(
            multiple_jobs=Case(
                When(total_jobs__gt=1, then=Value(True)),
                default=Value(False),
                output_field=BooleanField(),
            )
        )
        # Get the due_date of the summation from the SummationStatus object
        .annotate(
            summation_status_due_date=Subquery(
                summation_status.values("summation_due")
            )
        )
        # I need to add the annotation here for the 'evaluations_summary' to avoid
        # having the database hit for every user (which could possibly range into the
        # thousands in certain cases)
        # I have tried a number of ways to obtain what I'm looking for
        .annotate(
            evaluations_summary=Subquery(
                evaluations_set.order_by()
                .values("evaluation_type__name")
                .annotate(Count("evaluation_type"))
            )
        )
        # this annotation gives the error: Only one expression can be specified in the 
        # select list when the subquery is not introduced with EXISTS.
 
Run Code Online (Sandbox Code Playgroud)

是否有可能转换该模型方法注释?我很接近吗?