Naroju
Naroju

Reputation: 2667

Django nested Serializer filter to only one field, not all fields

I have two serializers like below. The output for the below snippet is Workers and with associated Ticket Counter details with all fields (ticket_counter,ticket_counter_name,worker). But I just need only one field that is ticket_counter_name.

class WorkerSerializer(serializers.ModelSerializer):

    ticket_counter = WorkerToCounterSerializer(many=True, read_only=True)

    class Meta:
        model = User
        fields = (
                  'username',
                  'ticket_counter',
                  )

class WorkerToCounterSerializer(serializers.ModelSerializer):
    ticket_counter = SerializerMethodField()
    ticket_counter_name = serializers.CharField(source='ticket_counter.ticket_counter_name')

    class Meta:
        model = WorkerToTicketCounter
        list_serializer_class = FilteredListSerializer
        fields = (
            'ticket_counter',
            'ticket_counter_name',
            'worker',
        )

    def get_ticket_counter(self, obj):
        return obj.ticket_counter.pk

class FilteredListSerializer(ListSerializer):
    def to_representation(self, data):
        data = data.filter(worker_to_ticket_counter_is_deleted=False)[:1]
        return super(FilteredListSerializer, self).to_representation(data)

What above snippet outputs

{
        "username": "xxxxxxxxxxx",
        "ticket_counter": [
            {
                "ticket_counter": 7,
                "ticket_counter_name": "Entrance Counter",
                "worker": 4,

            }
        ]
 }

But What I want is

 {
        "username": "xxxxxxxxxxx",
        "ticket_counter": "Entrance Counter"
 }

I just need the name of the ticket_counter_name. In my case, there can't be two ticket_counters for a worker. Obviously, it gives only one ticket_counter. Is it possible?

EDIT: using string StringRelatedField

{
    "username": "xxxxxxxxxxx",
    "ticket_counter": [
          "Entrance Counter",
          "xxxxxxxxxxxxxxxx",
          "xxxxxxxxxxxxxxxx",
          "xxxxxxxxxxxxxxxx"
    ]
}

EDIT: WorkerToTicketCounter Model

class WorkerToTicketCounter(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    ticket_counter = models.ForeignKey(TicketCounter, related_name="workers")
    worker = models.ForeignKey(User, related_name='ticket_counter')
    worker_to_ticket_counter_is_deleted = models.BooleanField(default=False)

Upvotes: 0

Views: 1420

Answers (2)

JPG
JPG

Reputation: 88499

If I'm understood correctly, you only need a SerializerMethodField to perform both filtering and string represantion.

class WorkerSerializer(serializers.ModelSerializer):
    ticket_counter = serializers.SerializerMethodField(read_only=True)

    def get_ticket_counter(self, user):
        qs = user.ticket_counter.filter(worker_to_ticket_counter_is_deleted=False)
        if qs.exists() and hasattr(qs.first().ticket_counter, 'ticket_counter_name'):
            return qs.first().ticket_counter.ticket_counter_name
        return None

    class Meta:
        model = User
        fields = ('username', 'ticket_counter',)

Upvotes: 1

neverwalkaloner
neverwalkaloner

Reputation: 47354

You can use StringRelatedField:

class WorkerSerializer(serializers.ModelSerializer):

    ticket_counter = StringRelatedField(many=True, read_only=True)

    class Meta:
        model = User
        fields = (
                  'username',
                  'ticket_counter',
                  )

Note to use StringRelatedField you should add __str__ method to your WorkerToTicketCounter model:

class WorkerToTicketCounter:
    ...
    def __str__(self):
        return self.ticket_counter.ticket_counter_name

Upvotes: 1

Related Questions