【发布时间】:2020-07-27 10:57:58
【问题描述】:
我目前有一个序列化程序,它使用两个 SerializerMethodField 访问同一个嵌套对象,导致两个数据库调用:
# models.py
class Onboarding(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
is_retailer_created = models.BooleanField(default=False)
is_complete = models.BooleanField(default=False)
# views.py
class StateView(RetrieveAPIView):
serializer_class = serializers.UserSerialiser
def get_object(self):
return self.request.user
# serializers.py
class UserSerialiser(serializers.ModelSerializer):
is_onboarded = serializers.SerializerMethodField()
is_loyalty_onboarded = serializers.SerializerMethodField()
class Meta:
model = models.User
fields = ('is_onboarded', 'is_loyalty_onboarded')
def get_is_onboarded(self, obj):
onboarding = obj.onboarding_set.first()
if onboarding:
return onboarding.is_retailer_created
return False
def get_is_loyalty_onboarded(self, obj):
onboarding = obj.onboarding_set.first()
if onboarding:
return onboarding.is_complete
return False
如果可能的话,我想把它整合到一个电话中。通常可以只使用prefetch_related,但由于get_object 返回的是特定用户(而不是queryset),我认为该解决方案在这里不起作用。
有没有办法让用户预取Onboarding 模型?还是只调用一次Onboarding 而不是两次?
【问题讨论】:
-
.first()看起来很奇怪。在以随机顺序检索所有记录之后。所以想象is_retailer_created对于某些人来说是True而对于其他人来说是False。那么这意味着结果将是随机的。 -
通常您可以使用
.annotate(..)对每个组执行聚合/子查询:docs.djangoproject.com/en/dev/ref/models/querysets/#annotate -
@WillemVanOnsem - 这是预期行为 - 目前,每个用户只有一个入职模型,所以现在
.first()可以(尽管它是错误代码),稍后会更新 -就annotate而言,我看不出在这种情况下它是如何工作的,因为没有查询集可以操作。我仍然会为每个SerializerMethodField调用两次,不是吗? -
那么应该使用
OneToOneField,因为这是一个具有唯一性约束的ForeignKey,因此这意味着每个User都有一个Onboarding。至于get_object。诀窍是在get_queryset中进行注释,因为get_object采用查询集,然后获取一条记录(例如pk 匹配的位置)。因此,即使是提供get_object方法的SingleObjectMixin,也会在后台使用get_queryset。 -
您可以分享您正在使用的视图/视图集吗?
标签: django django-models serialization django-rest-framework