我正在尝试加快我的 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 秒才能返回数百个查询。