Skip to content

Commit 03c2ef1

Browse files
954-Ivoryauvipy
andauthored
Fixes instance check in ListSerializer.to_representation (#8726) (#8727)
* Fixes 'RelatedManager' object is not iterable in ListSerializer.to_representation.(#8726) * Change to only BaseManager * Commit unit test * Update tests/test_serializer_lists.py * Update tests/test_serializer_lists.py * Update tests/test_serializer_lists.py * Update tests/test_serializer_lists.py * Update tests/test_serializer_lists.py * Update tests/test_serializer_lists.py * Format import * Format import Co-authored-by: Asif Saif Uddin <[email protected]>
1 parent 9e56f54 commit 03c2ef1

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

rest_framework/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ def to_representation(self, data):
683683
"""
684684
# Dealing with nested relationships, data can be a Manager,
685685
# so, first get a queryset from the Manager if needed
686-
iterable = data.all() if isinstance(data, models.Manager) else data
686+
iterable = data.all() if isinstance(data, models.manager.BaseManager) else data
687687

688688
return [
689689
self.child.to_representation(item) for item in iterable

tests/models.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from django.contrib.auth.models import User
44
from django.db import models
5+
from django.db.models import QuerySet
6+
from django.db.models.manager import BaseManager
57
from django.utils.translation import gettext_lazy as _
68

79

@@ -124,3 +126,27 @@ class OneToOnePKSource(RESTFrameworkModel):
124126
target = models.OneToOneField(
125127
OneToOneTarget, primary_key=True,
126128
related_name='required_source', on_delete=models.CASCADE)
129+
130+
131+
class CustomManagerModel(RESTFrameworkModel):
132+
class CustomManager:
133+
def __new__(cls, *args, **kwargs):
134+
cls = BaseManager.from_queryset(
135+
QuerySet
136+
)
137+
return cls
138+
139+
objects = CustomManager()()
140+
# `CustomManager()` will return a `BaseManager` class.
141+
# We need to instantiation it, so we write `CustomManager()()` here.
142+
143+
text = models.CharField(
144+
max_length=100,
145+
verbose_name=_("Text comes here"),
146+
help_text=_("Text description.")
147+
)
148+
149+
o2o_target = models.ForeignKey(OneToOneTarget,
150+
help_text='OneToOneTarget',
151+
verbose_name='OneToOneTarget',
152+
on_delete=models.CASCADE)

tests/test_serializer_lists.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
from rest_framework import serializers
88
from rest_framework.exceptions import ErrorDetail
9+
from tests.models import (
10+
CustomManagerModel, NullableOneToOneSource, OneToOneTarget
11+
)
912

1013

1114
class BasicObject:
@@ -683,3 +686,43 @@ def test_min_max_length_six_items(self):
683686
assert min_serializer.validated_data == input_data
684687

685688
assert not max_min_serializer.is_valid()
689+
690+
691+
@pytest.mark.django_db()
692+
class TestToRepresentationManagerCheck:
693+
"""
694+
https://github.com/encode/django-rest-framework/issues/8726
695+
"""
696+
697+
def setup_method(self):
698+
class CustomManagerModelSerializer(serializers.ModelSerializer):
699+
class Meta:
700+
model = CustomManagerModel
701+
fields = '__all__'
702+
703+
class OneToOneTargetSerializer(serializers.ModelSerializer):
704+
my_model = CustomManagerModelSerializer(many=True, source="custommanagermodel_set")
705+
706+
class Meta:
707+
model = OneToOneTarget
708+
fields = '__all__'
709+
depth = 3
710+
711+
class NullableOneToOneSourceSerializer(serializers.ModelSerializer):
712+
target = OneToOneTargetSerializer()
713+
714+
class Meta:
715+
model = NullableOneToOneSource
716+
fields = '__all__'
717+
718+
self.serializer = NullableOneToOneSourceSerializer
719+
720+
def test(self):
721+
o2o_target = OneToOneTarget.objects.create(name='OneToOneTarget')
722+
NullableOneToOneSource.objects.create(
723+
name='NullableOneToOneSource',
724+
target=o2o_target
725+
)
726+
queryset = NullableOneToOneSource.objects.all()
727+
serializer = self.serializer(queryset, many=True)
728+
assert serializer.data

0 commit comments

Comments
 (0)