39

I am serializing the built-in django Group model and would like to add a field to the serializer that counts the number of users in the group. I am currently using the following serializer:

class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = Group
        fields = ('id', 'name', 'user_set')

This returns the group ID and name and an array of users (user IDs) in the group:

{
    "id": 3,
    "name": "Test1",
    "user_set": [
      9
    ]
}

What I would like instead as output is something like:

{
    "id": 3,
    "name": "Test1",
    "user_count": 1
}

Any help would be appreciated. Thanks.

0

3 Answers 3

82

A bit late but short answer. Try this

user_count = serializers.IntegerField(
    source='user_set.count', 
    read_only=True
)
Sign up to request clarification or add additional context in comments.

5 Comments

Awesome answer . . . . this will also work user_count = serializers.ReadOnlyField( source='user_set.count' )
Is it possible to filter user_set too? something like: serializers.IntegerField(source='user_set.count', read_only=True, filters={'user_set.x':'y'})
not sure. these are the available options for a serializer field. i think the best way will be to use serializers.SerializerMethodField() where you can do any type of custom work including filtering
Nice answer.One question will it fire separate queries for each object to get count of onetomany relation ?
@PrashantRajput. i think that depends on how you have initialized your queryset or get_object() etc with select_related or prefetch_related. you can take a look here. But looks like at the moment you cannot specify in serializer field to use select_related or prefetch_related for source attr. here is an open issue for this. source attribute doc
52

This should work

class GroupSerializer(serializers.ModelSerializer):

    user_count = serializers.SerializerMethodField()

    class Meta:
        model = Group
        fields = ('id', 'name','user_count')

    def get_user_count(self, obj):
        return obj.user_set.count()

This adds a user_count field to your serializer whose value is set by get_user_count, which will return the length of the user_set.

You can find more information on SerializerMethodField here: http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

5 Comments

Thanks, works like a charm. Just had to change "obj.user_set" to "obj.user_set.all()"
maybe obj.user_set.count() or something
This answer is very useful when mongoengine is used and reverse relationships are not available.
You can remove self from parameters and add @staticmethod decorator on your definition. :)
@Elmux would it change something or would it just be prettier/ more pythonic?
4

Everyone's answer looks great. And I would like to contribute another options here - to use @property if-and-only-if you can modify the target model.

Assume you can modify the Group model.

class Group(models.Model):

    @property
    def user_count(self):
        return self.user_set.count

Then you can simply add 'user_count' to fields in your serializer.

I'm using this approach but I'm thinking to switch to the serializer approach as other's answer here. Thanks everyone.

4 Comments

I'd rather not touch the model at all. It's the API's responsibility to provide extra functionality and fields.
If the count value is needed by both admin and restful, it would be better to add an extra property to the model - ensure both sides are using same code, as well as dont-repeat-yourself.
what is user_set ?
user_set is a property inside Group model. Just a SET of users belong to Group.

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.