mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-24 02:24:03 +03:00
Fix pk-only optimization for properties (#7142)
* Add callable/prop tests for pk-only optimization * Fix related field pk-only optimization for props
This commit is contained in:
parent
b3e02592d0
commit
f323049ecc
|
@ -175,8 +175,13 @@ class RelatedField(Field):
|
|||
value = attribute_instance.serializable_value(self.source_attrs[-1])
|
||||
if is_simple_callable(value):
|
||||
# Handle edge case where the relationship `source` argument
|
||||
# points to a `get_relationship()` method on the model
|
||||
value = value().pk
|
||||
# points to a `get_relationship()` method on the model.
|
||||
value = value()
|
||||
|
||||
# Handle edge case where relationship `source` argument points
|
||||
# to an instance instead of a pk (e.g., a `@property`).
|
||||
value = getattr(value, 'pk', value)
|
||||
|
||||
return PKOnlyObject(pk=value)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
|
|
@ -37,6 +37,15 @@ class ManyToManySource(RESTFrameworkModel):
|
|||
class ForeignKeyTarget(RESTFrameworkModel):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def get_first_source(self):
|
||||
"""Used for testing related field against a callable."""
|
||||
return self.sources.all().order_by('pk')[0]
|
||||
|
||||
@property
|
||||
def first_source(self):
|
||||
"""Used for testing related field against a property."""
|
||||
return self.sources.all().order_by('pk')[0]
|
||||
|
||||
|
||||
class UUIDForeignKeyTarget(RESTFrameworkModel):
|
||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
|
||||
|
|
|
@ -30,6 +30,25 @@ class ForeignKeyTargetSerializer(serializers.ModelSerializer):
|
|||
fields = ('id', 'name', 'sources')
|
||||
|
||||
|
||||
class ForeignKeyTargetCallableSourceSerializer(serializers.ModelSerializer):
|
||||
first_source = serializers.PrimaryKeyRelatedField(
|
||||
source='get_first_source',
|
||||
read_only=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = ForeignKeyTarget
|
||||
fields = ('id', 'name', 'first_source')
|
||||
|
||||
|
||||
class ForeignKeyTargetPropertySourceSerializer(serializers.ModelSerializer):
|
||||
first_source = serializers.PrimaryKeyRelatedField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ForeignKeyTarget
|
||||
fields = ('id', 'name', 'first_source')
|
||||
|
||||
|
||||
class ForeignKeySourceSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ForeignKeySource
|
||||
|
@ -389,6 +408,34 @@ class PKForeignKeyTests(TestCase):
|
|||
assert len(queryset) == 1
|
||||
|
||||
|
||||
class PKRelationTests(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.target = ForeignKeyTarget.objects.create(name='target-1')
|
||||
ForeignKeySource.objects.create(name='source-1', target=self.target)
|
||||
ForeignKeySource.objects.create(name='source-2', target=self.target)
|
||||
|
||||
def test_relation_field_callable_source(self):
|
||||
serializer = ForeignKeyTargetCallableSourceSerializer(self.target)
|
||||
expected = {
|
||||
'id': 1,
|
||||
'name': 'target-1',
|
||||
'first_source': 1,
|
||||
}
|
||||
with self.assertNumQueries(1):
|
||||
self.assertEqual(serializer.data, expected)
|
||||
|
||||
def test_relation_field_property_source(self):
|
||||
serializer = ForeignKeyTargetPropertySourceSerializer(self.target)
|
||||
expected = {
|
||||
'id': 1,
|
||||
'name': 'target-1',
|
||||
'first_source': 1,
|
||||
}
|
||||
with self.assertNumQueries(1):
|
||||
self.assertEqual(serializer.data, expected)
|
||||
|
||||
|
||||
class PKNullableForeignKeyTests(TestCase):
|
||||
def setUp(self):
|
||||
target = ForeignKeyTarget(name='target-1')
|
||||
|
|
Loading…
Reference in New Issue
Block a user