Django - 当提供 .values() 时,StringRelatedField() 不适用于查询结果
Django - StringRelatedField() not applied to query results when .values() provided
在我的 Django 应用程序中,我发现当序列化程序 class 上的 StringRelatedField()
未被应用时,当该序列化程序用于一组字段值具有的过滤器查询时已指定 - 尽管如果查询 return 的所有字段它确实有效。哇,那是一口,让我分解一下 -
我有两个模型,Report
和 User
;每个 Report
都与一个 User
相关联。理想情况下,我想通过 get_queryset
查询报告,并且在每个报告记录中,关联的 user
的值应该是 StringRelatedField()
的结果,return 的值 __str__
User
模型(即用户的名字和姓氏)上的方法。
如果我的查询 return 包含所有字段,这非常有效...所以查询
Report.objects.filter(location__within=some_other_model.region)
成功了。
但是,我发现只查询我实际需要的 values
可以大大提高性能,所以我更喜欢这样查询:
Report.objects.filter(location__within=some_other_model.region).values('id',
'location',
'user',)
但该查询的结果具有 User
table 记录的 UUID 外键,它们似乎没有被 StringRelatedField()
替换。
下面,我有 Report
的视图和序列化程序,以及 User
模型。
# report/view.py
class ReportViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = ReportReadSerializer
def get_queryset(self):
some_other_model = get_object_or_404(Organization, pk='some_other_model_id')
# remove the .values() and this works correctly
return Report.objects.filter(location__within=some_other_model.region).values('id',
'location',
'user',)
# report/serializers.py
class ReportReadSerializer(serializers.GeoFeatureModelSerializer):
location = serializers.GeometryField(precision=4)
user = StringRelatedField()
class Meta:
model = Observation
geo_field = 'location'
fields = [
'id',
'location',
'user',
]
# user/models.py
class User(SoftDeletionModel):
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
任何指导将不胜感激。
这是 StringRelatedField()
的预期行为
StringRelatedField
returns str
值的表示 和你的情况,用户有一个 integer 值。如果您使用 QuerySet
(不调用 values()
),用户将有一个 User
实例,因此 str
表示将为您提供正确的结果。
您感到性能有所提高,因为 values('id', 'location', 'user', )
从单个 table 中获取值(请注意,调用 user
不会在此处进行内部联接)并且有没有机会出现 N+1
问题。但是,如果您使用用户的 str
方法,Django 将进行内部连接,并且会出现 N+1
问题,因此您将遇到性能问题。
所以,你有两个选择,
- 使用值并忽略
User
的表示
- 使用
select_related()
class ReportViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = ReportReadSerializer
def get_queryset(self):
some_other_model = get_object_or_404(Organization, pk='some_other_model_id')
return Report.objects.filter(
location__within=some_other_model.region
)<b>.select_related("user")</b>
在我的 Django 应用程序中,我发现当序列化程序 class 上的 StringRelatedField()
未被应用时,当该序列化程序用于一组字段值具有的过滤器查询时已指定 - 尽管如果查询 return 的所有字段它确实有效。哇,那是一口,让我分解一下 -
我有两个模型,Report
和 User
;每个 Report
都与一个 User
相关联。理想情况下,我想通过 get_queryset
查询报告,并且在每个报告记录中,关联的 user
的值应该是 StringRelatedField()
的结果,return 的值 __str__
User
模型(即用户的名字和姓氏)上的方法。
如果我的查询 return 包含所有字段,这非常有效...所以查询
Report.objects.filter(location__within=some_other_model.region)
成功了。
但是,我发现只查询我实际需要的 values
可以大大提高性能,所以我更喜欢这样查询:
Report.objects.filter(location__within=some_other_model.region).values('id',
'location',
'user',)
但该查询的结果具有 User
table 记录的 UUID 外键,它们似乎没有被 StringRelatedField()
替换。
下面,我有 Report
的视图和序列化程序,以及 User
模型。
# report/view.py
class ReportViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = ReportReadSerializer
def get_queryset(self):
some_other_model = get_object_or_404(Organization, pk='some_other_model_id')
# remove the .values() and this works correctly
return Report.objects.filter(location__within=some_other_model.region).values('id',
'location',
'user',)
# report/serializers.py
class ReportReadSerializer(serializers.GeoFeatureModelSerializer):
location = serializers.GeometryField(precision=4)
user = StringRelatedField()
class Meta:
model = Observation
geo_field = 'location'
fields = [
'id',
'location',
'user',
]
# user/models.py
class User(SoftDeletionModel):
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
任何指导将不胜感激。
这是 StringRelatedField()
StringRelatedField
returns str
值的表示 和你的情况,用户有一个 integer 值。如果您使用 QuerySet
(不调用 values()
),用户将有一个 User
实例,因此 str
表示将为您提供正确的结果。
您感到性能有所提高,因为 values('id', 'location', 'user', )
从单个 table 中获取值(请注意,调用 user
不会在此处进行内部联接)并且有没有机会出现 N+1
问题。但是,如果您使用用户的 str
方法,Django 将进行内部连接,并且会出现 N+1
问题,因此您将遇到性能问题。
所以,你有两个选择,
- 使用值并忽略
User
的表示 - 使用
select_related()
class ReportViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = ReportReadSerializer
def get_queryset(self):
some_other_model = get_object_or_404(Organization, pk='some_other_model_id')
return Report.objects.filter(
location__within=some_other_model.region
)<b>.select_related("user")</b>