diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 7037c07cd..eae6a0b2e 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -683,7 +683,7 @@ class ListSerializer(BaseSerializer): """ # Dealing with nested relationships, data can be a Manager, # so, first get a queryset from the Manager if needed - iterable = data.all() if isinstance(data, models.Manager) else data + iterable = data.all() if isinstance(data, models.manager.BaseManager) else data return [ self.child.to_representation(item) for item in iterable diff --git a/tests/models.py b/tests/models.py index 666e9f003..88e3d8dca 100644 --- a/tests/models.py +++ b/tests/models.py @@ -2,6 +2,8 @@ import uuid from django.contrib.auth.models import User from django.db import models +from django.db.models import QuerySet +from django.db.models.manager import BaseManager from django.utils.translation import gettext_lazy as _ @@ -124,3 +126,27 @@ class OneToOnePKSource(RESTFrameworkModel): target = models.OneToOneField( OneToOneTarget, primary_key=True, related_name='required_source', on_delete=models.CASCADE) + + +class CustomManagerModel(RESTFrameworkModel): + class CustomManager: + def __new__(cls, *args, **kwargs): + cls = BaseManager.from_queryset( + QuerySet + ) + return cls + + objects = CustomManager()() + # `CustomManager()` will return a `BaseManager` class. + # We need to instantiation it, so we write `CustomManager()()` here. + + text = models.CharField( + max_length=100, + verbose_name=_("Text comes here"), + help_text=_("Text description.") + ) + + o2o_target = models.ForeignKey(OneToOneTarget, + help_text='OneToOneTarget', + verbose_name='OneToOneTarget', + on_delete=models.CASCADE) diff --git a/tests/test_serializer_lists.py b/tests/test_serializer_lists.py index 4b60643a8..10463d29a 100644 --- a/tests/test_serializer_lists.py +++ b/tests/test_serializer_lists.py @@ -6,6 +6,9 @@ from django.utils.datastructures import MultiValueDict from rest_framework import serializers from rest_framework.exceptions import ErrorDetail +from tests.models import ( + CustomManagerModel, NullableOneToOneSource, OneToOneTarget +) class BasicObject: @@ -683,3 +686,43 @@ class TestMaxMinLengthListSerializer: assert min_serializer.validated_data == input_data assert not max_min_serializer.is_valid() + + +@pytest.mark.django_db() +class TestToRepresentationManagerCheck: + """ + https://github.com/encode/django-rest-framework/issues/8726 + """ + + def setup_method(self): + class CustomManagerModelSerializer(serializers.ModelSerializer): + class Meta: + model = CustomManagerModel + fields = '__all__' + + class OneToOneTargetSerializer(serializers.ModelSerializer): + my_model = CustomManagerModelSerializer(many=True, source="custommanagermodel_set") + + class Meta: + model = OneToOneTarget + fields = '__all__' + depth = 3 + + class NullableOneToOneSourceSerializer(serializers.ModelSerializer): + target = OneToOneTargetSerializer() + + class Meta: + model = NullableOneToOneSource + fields = '__all__' + + self.serializer = NullableOneToOneSourceSerializer + + def test(self): + o2o_target = OneToOneTarget.objects.create(name='OneToOneTarget') + NullableOneToOneSource.objects.create( + name='NullableOneToOneSource', + target=o2o_target + ) + queryset = NullableOneToOneSource.objects.all() + serializer = self.serializer(queryset, many=True) + assert serializer.data