rkm2
rkm2

Reputation: 53

How to get values from ForeignKey's related model in Django queryset?

I'm having trouble accessing a field in a related model using a foreign key.

I have two models, Person and Party as outlined below:

class Person(models.Model):
    title = models.CharField(max_length = 4, blank=True, null=True)
    first = models.CharField(max_length = 30, blank=True, null=True)
    last = models.CharField(max_length = 30, blank=True, null=True)
    party = models.ForeignKey(Party, related_name = 'parties', on_delete=models.CASCADE, blank=True, null=True)

    def __str__(self):
        return self.id


class Party(models.Model):

    party_name = models.CharField(max_length = 50)
    party_code = models.CharField(max_length = 5)

    def __str__(self):
        return self.party_name

I'm trying to get a count of people in each party. I'd like the result to look like:

[{
    "party_name": "Democrat",
    "total_members": 93
},
{
    "party_name": "Republican",
    "total_members": 32
},
{
    "party_name": "Non-Partisan",
    "total_members": 34
}]

My serializer is as follows:

class CountPartiesSerializer(serializers.ModelSerializer):

    total_members = serializers.IntegerField()

    class Meta:
        model = Person
        fields = ('id', 'party', 'total_members')

And my viewset is as follows:

class CountPartiesViewSet(DefaultsMixin, viewsets.ModelViewSet):
    queryset = Person.objects.values('party__party_name').annotate(total_members = Count('id'))
    serializer_class = CountPartiesSerializer

But this results in the following:

[{
    "party": null,
    "total_members": 34
},
{
    "party": null,
    "total_members": 93
},
{
    "party": null,
    "total_members": 32
}]

I've tried a million different things and I know I'm missing something, but I can't figure out how to get this working. Any advice would be much appreciated!

Upvotes: 1

Views: 627

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599610

You're serializing the wrong thing. Your serializer should be based on Party, and you can then add the count of members.

Edit

class PartySerializer(serializers.ModelSerializer):
    total_members = serializers.IntegerField()

    class Meta:
        model = Party
        fields = ('name', 'total_members')


class PartyViewSet(DefaultsMixin, viewsets.ModelViewSet):
    queryset = Party.objects.values('name').annotate(total_members=Count('parties'))
    serializer_class = PartySerializer

You do of course have a relation between party and person: it is the reverse relationship of your foreign key. Note, the name you have chosen for the related_name there is confusing; it should be 'people', or just leave it as the default, which would be 'person_set'.

Upvotes: 1

Related Questions