0

我正在尝试加快我的 API。

我需要(至少我假设我需要)SerializerMethodField用来计算我需要包含在对象中的不同信息位。

当我这样做时,在这些方法中,我必须获取相关_set数据——这些数据最终会进入数据库。

正如您可以想象的那样,一旦我拥有大量用户的列表(例如:当我在 Web API 中显示所有用户时),由于对数据库的这些点击,它需要永远返回。

我不确定处理这个问题的最佳方法 - 我相信prefetch_related和/或者select_related是答案,我只是不确定实现这些功能的最佳方法。

我的代码如下所示(pastebin 版本):


# MODELS
 
class User(models.Model):
    name = models.CharField(max_length=50)
    # ...etc...
 
class Assignment(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.PROTECT
    )
    job = models.ForeignKey(Job, on_delete=models.PROTECT)
    location = models.ForeignKey(Location, on_delete=models.PROTECT)
 
# SERIALIZER
 
class UserSerializer(serializers.HyperlinkedModelSerializer):
    assignment_job = serializers.SerializerMethodField()
    multiple_locations = serializers.SerializerMethodField()
    multiple_jobs = serializers.SerializerMethodField()
 
    class Meta:
        model = User
        fields = [
            "url",
            "id",
            "username",
            "first_name",
            "last_name",
            "full_name",
            "email",
            "is_staff",
            "assignment_job",
            "multiple_locations",
            "multiple_jobs",
        ]
 
    def get_assignment_job(self, obj):
        assignment = obj.assignment_set.get(primary=True)
        return assignment.job.description
 
    def get_multiple_locations(self, obj):
        location_count = obj.assignment_set.filter(
            end_date__isnull=True
        ).aggregate(total_locations=Count("location"))
        if location_count["total_locations"] > 1:
            return True
        return False
 
    def get_multiple_jobs(self, obj):
        job_count = obj.assignment_set.filter(end_date__isnull=True).aggregate(
            total_jobs=Count("job")
        )
        if job_count["total_jobs"] > 1:
            return True
        return False
 
 
# SERIALIZER VIEW
 
class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
 
    def get_queryset(self):
        users = get_observable_users(self.request.user)
        return users
 
 
# get_observable_users Method
# this returns the correct users - I've tried adding the prefetch_related here
 
def get_observable_users(user):
    user_assignments = Assignment.active.filter(user=user)
    user_jobs = user_assignments.values_list("job", flat=True)
    locations = user_assignments.values_list("location", flat=True)
    administrative_job_observations = JobObservation.objects.filter(
        observer_job__in=user_jobs,
        restrict_to_location=False,
    )
    observee_jobs = JobObservation.objects.filter(
        observer_job__in=user_jobs
    ).values_list("observee_job", flat=True)
    if administrative_job_observations:
        people_assignments = Assignment.objects.filter(job__in=observee_jobs)
    else:
        people_assignments = Assignment.objects.filter(
            job__in=observee_jobs, location__in=locations
        )
    all_assignments = user_assignments | people_assignments
    all_user_ids = all_assignments.values_list("user", flat=True)
    user_list = User.objects.prefetch_related("assignment_set").filter(
        id__in=all_user_ids
    )
    return user_list

我不确定我prefetch_related是否在这里使用正确,因为它仍然会为每个User被序列化的数据库命中数据库。

关于如何处理和优化这个的任何建议?对于 200 多个用户的列表,平均需要 3-5 秒才能返回数百个查询。

4

0 回答 0