1

I use one Serializer in many different places in my project. I need to use one annotation but the problem is that I don't want to annotate it in all views so I would like to do universal annotation in the Serializer itself.

It is possible?

Now I need to do this before every serialization:

City.objects....filter....annotate(
                number_of_users_here_now=Count('current_userprofiles'))

I tried:

class NumberOfUsersInCityNowField(serializers.Field):
    def to_native(self, value):
        count = value.annotate(
            number_of_users_here_now=Count('current_userprofiles'))['current_userprofiles__count']
        return count


class CityMapSerializer(serializers.ModelSerializer):
    number_of_users_here_now = NumberOfUsersInCityNowField()

    class Meta:
        model = City
        fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address')

This Serializer returns:

AttributeError at /api/ajax-check-trip-creation Got AttributeError when attempting to get a value for field number_of_users_here_now on serializer CityMapSerializer. The serializer field might be named incorrectly and not match any attribute or key on the City instance. Original exception text was: 'City' object has no attribute 'number_of_users_here_now'.

EDIT

class NumberOfUsersInCityNowField(serializers.PrimaryKeyRelatedField):
    def get_queryset(self):
        return City.objects.annotate(
        number_of_users_here_now=Count('current_userprofiles'))

class CityMapSerializer(serializers.ModelSerializer):
    # number_of_users_here_now = serializers.IntegerField()
    number_of_users_here_now = NumberOfUsersInCityNowField()
    class Meta:
        model = City
        fields = ('place_id', 'lat', 'lng', 'number_of_users_here_now', 'formatted_address')

But

serializers.CityMapSerializer(City.objects.all()[:3],many=True).data

still returns:

AttributeError: 'City' object has no attribute 'number_of_users_here_now'
2
  • you have the same field name in the model? Commented Jan 8, 2018 at 15:46
  • No, that's not a native field. I need to add count of userprofiles for each city. Commented Jan 8, 2018 at 15:47

1 Answer 1

1

You can just use queryset's count method with SerializerMethodField:

class CityMapSerializer(serializers.ModelSerializer):
    number_of_users_here_now = SerializerMethodField()

    def get_number_of_users_here_now (self, obj):
        return obj.current_userprofiles.count()

UPD

Also to avoid n+1 queries you can try to implement get_queryset method of NumberOfUsersInCityNowField serializer:

class NumberOfUsersInCityNowField(serializers.PrimaryKeyRelatedField):
    def get_queryset(self):
        return City.objects.annotate(
        number_of_users_here_now=Count('current_userprofiles'))['current_userprofiles__count']
Sign up to request clarification or add additional context in comments.

5 Comments

I wan't to avoid doing this since it access the database for every city, not just once as it is with annotating.
@MilanoSlesarik yes you are right, try to inherited from PrimaryKeyRelatedField and override get_queryset method.
Your solution seems to be what I want but unfortunately it returns the same error. I've added the code at the bottom of the question.
The City is a foreign key in model UserProfile with related_name='current_userprofiles'
@MilanoSlesarik sorry, cannot suggest you anything better. Iif you will not find the solution probably you should try mixin class which implements annotation and add it to all your view.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.