Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ModelSerializer with SerializerMethodField and overriding to_representation #27

Open
famdude opened this issue Jan 9, 2024 · 11 comments

Comments

@famdude
Copy link

famdude commented Jan 9, 2024

I have a ModelSerializer that contains some SerializerMethodFields and I need to override the to_representation method as well.
for instance:

from adrf.serializers import ModelSerializer as AsyncModelSerializer

class SampleSerializer(AsyncModelSerializer):
    remaining = serializers.SerializerMethodField(read_only=True)
    class Meta:
        model = MyModel
        fields = "__all__"
    def to_representation(self, instance):
        representation = super().to_representation(instance)
        # do some stuff here
        return representation

this is the APIView I have:

from adrf.views import APIView as AsyncAPIView

class SampleView(AsyncAPIView):
    permission_classes = [IsAuthenticated]
    user = request.user
        myObj = MyModel.objects.filter(
            userpackage_package__user=user,
            purchase_start_time__lte=timezone.localtime(),
            end_date__gte=timezone.localdate(),
        )
        serializer = SampleSerializer(
            myObj, many=True, context={"user": user}
        )
        return Response({"data": await serializer.adata}, status=status.HTTP_200_OK)

but I get this error: 'SerializerMethodField' object has no attribute 'ato_representation'

@KShoukry
Copy link

KShoukry commented Jan 10, 2024

@famdude you need to change def to_representation to async def ato_representation

However there is a different issue, this works:

async def ato_representation(self, instance):
    return { }

this throws 'SerializerMethodField' object has no attribute 'ato_representation':

async def ato_representation(self, instance):
    representation = await super().ato_representation(instance)
    return representation

@KShoukry
Copy link

I still can't find a way to make this work while calling the super.to_representation function

@KShoukry
Copy link

KShoukry commented Jan 10, 2024

Got it to finally work with this (but it feels dirty):
Disclaimer: I am new to Django & Python

class AsyncCompanySerializer(AsyncModelSerializer):
    class Meta:
        model = Company
        fields = ['id', 'name']


class AsyncNoorUserSerializer(AsyncModelSerializer):
    companies = serializers.SerializerMethodField()

    class Meta:
        model = NoorUser
        fields = ['id', 'username', 'preferred_lang', 'companies']

    async def get_companies(self, obj):
        roles = await sync_to_async(list)(Role.objects.filter(user=obj).select_related('company').all())
        companies = await AsyncCompanySerializer([role.company for role in roles], many=True).adata
        return companies

    async def ato_representation(self, instance):
        representation = super().to_representation(instance)
        representation['companies'] = await representation['companies']
        return representation

@KShoukry
Copy link

KShoukry commented Jan 11, 2024

@famdude This is the only way it worked for me but feels wrong:

class AsyncUserSerializer(AsyncModelSerializer):
    companies = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ['id', 'username', 'preferred_lang', 'companies']

    async def get_companies(self, obj):
        roles = await sync_to_async(list)(Role.objects.filter(user=obj).select_related('company').all())
        companies = await AsyncCompanySerializer([role.company for role in roles], many=True).adata
        return companies

    async def ato_representation(self, instance):
        representation = super().to_representation(instance)
        representation['companies'] = await representation['companies']
        return representation

@em1208
Copy link
Owner

em1208 commented Jan 17, 2024

@KShoukry The issue is that SerializerMethodField does not currently support async methods, so if you instead define def get_companies(self, obj) it will work without having to override async def ato_representation. I hope this helps!

@famdude
Copy link
Author

famdude commented Jan 20, 2024

@em1208 That's not the solution! I NEED to override to_represetation or ato_representation, because I have some essential calculations to do there.
what do you mean by "SerializerMethodField does not currently support async methods"? you mean django has not supported it yet? the method is a drf method, not a django method.

@em1208
Copy link
Owner

em1208 commented Jan 20, 2024

@famdude SerializerMethodField is a Django Rest Framework field and not everything in DRF is currently supported by adrf in an async way. If you still require your SerializerMethodField to be async then you can follow the solution #27 (comment) because the value returned by the method needs to be manually awaited.

@lybrain
Copy link

lybrain commented Jan 21, 2024

@em1208 hello, thank you and all the contributors for the hard work you've done! I saw the codebase and just wanted to ask if it is safe to use ModelViewSet, permissions, filters, serializers ... for production, how well do they support async mode?

@em1208
Copy link
Owner

em1208 commented Jan 22, 2024

@lybrain Thanks for your kind words. It's is safe to use adrf for production and you can verify the source code yourself but as mentioned adrf does not support everything that Django Rest Framework provides in an async way so it depends on your requirements if it will be useful to you.

@famdude
Copy link
Author

famdude commented Apr 20, 2024

@em1208 As I really need it, I want to know do you have any plan to implement it? or other contributors should look at it?

@em1208
Copy link
Owner

em1208 commented Apr 20, 2024

@famdude no plan at the moment. Happy to review a PR for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants