From fc08007df4ca5073e8212a23695b8c2fe64e705d Mon Sep 17 00:00:00 2001 From: Shil Date: Thu, 30 Mar 2023 01:59:04 +0200 Subject: [PATCH] Fixed test cases --- rest_framework/relations.py | 3 ++- tests/test_relations.py | 45 ++++++++++++++++++++++++++++++++++++- tests/utils.py | 4 +++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 2f45f1de2..be020ea28 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -72,6 +72,7 @@ class PKOnlyObject: instance, but still want to return an object with a .pk attribute, in order to keep the same interface as a regular model instance. """ + def __init__(self, pk): self.pk = pk @@ -469,7 +470,7 @@ class SlugRelatedField(RelatedField): if "__" in slug: # handling nested relationship defined by double underscore slug = slug.replace('__', '.') - return attrgetter(obj, slug) + return attrgetter(slug)(obj) class ManyRelatedField(Field): diff --git a/tests/test_relations.py b/tests/test_relations.py index 7a4db1c48..f11b08119 100644 --- a/tests/test_relations.py +++ b/tests/test_relations.py @@ -304,7 +304,7 @@ class TestSlugRelatedField(APISimpleTestCase): self.queryset = MockQueryset([ MockObject(pk=1, name='foo'), MockObject(pk=2, name='bar'), - MockObject(pk=3, name='baz') + MockObject(pk=3, name='baz'), ]) self.instance = self.queryset.items[2] self.field = serializers.SlugRelatedField( @@ -342,6 +342,49 @@ class TestSlugRelatedField(APISimpleTestCase): field.to_internal_value(self.instance.name) +class TestNestedSlugRelatedField(APISimpleTestCase): + def setUp(self): + self.queryset = MockQueryset([ + MockObject(pk=1, name='foo', nested=MockObject(pk=2, name='bar')), + MockObject(pk=3, name='hello', nested=MockObject(pk=4, name='world')), + MockObject(pk=3, name='harry', nested=MockObject(pk=4, name='potter')) + ]) + self.instance = self.queryset.items[2] + self.field = serializers.SlugRelatedField( + slug_field='nested__name', queryset=self.queryset + ) + + def test_slug_related_lookup_exists(self): + instance = self.field.to_internal_value(self.instance.nested.name) + assert instance is self.instance + + def test_slug_related_lookup_does_not_exist(self): + with pytest.raises(serializers.ValidationError) as excinfo: + self.field.to_internal_value('doesnotexist') + msg = excinfo.value.detail[0] + assert msg == 'Object with nested__name=doesnotexist does not exist.' + + def test_slug_related_lookup_invalid_type(self): + with pytest.raises(serializers.ValidationError) as excinfo: + self.field.to_internal_value(BadType()) + msg = excinfo.value.detail[0] + assert msg == 'Invalid value.' + + def test_representation(self): + representation = self.field.to_representation(self.instance) + assert representation == self.instance.nested.name + + def test_overriding_get_queryset(self): + qs = self.queryset + + class NoQuerySetSlugRelatedField(serializers.SlugRelatedField): + def get_queryset(self): + return qs + + field = NoQuerySetSlugRelatedField(slug_field='nested__name') + field.to_internal_value(self.instance.nested.name) + + class TestManyRelatedField(APISimpleTestCase): def setUp(self): self.instance = MockObject(pk=1, name='foo') diff --git a/tests/utils.py b/tests/utils.py index 06e5b9abe..639785951 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,3 +1,4 @@ +from operator import attrgetter from django.core.exceptions import ObjectDoesNotExist from django.urls import NoReverseMatch @@ -26,7 +27,7 @@ class MockQueryset: def get(self, **lookup): for item in self.items: if all([ - getattr(item, key, None) == value + attrgetter(key.replace('__', '.'))(item) == value for key, value in lookup.items() ]): return item @@ -39,6 +40,7 @@ class BadType: will raise a `TypeError`, as occurs in Django when making queryset lookups with an incorrect type for the lookup value. """ + def __eq__(self): raise TypeError()