Получить каждое отношение m2m в модели как отдельный объект в сериализаторе DRF

#django #django-models #django-rest-framework

#django #django-модели #django-rest-framework

Вопрос:

У меня есть модельная юрисдикция, которая имеет отношение M2M к франшизе. И я использую ModelViewSet для юрисдикции. models.py

 class Franchise(models.Model):
    name = models.CharField('Name', max_length=255, db_index=True)


class Jurisdiction(models.Model):
    franchise = models.ManyToManyField(
        Franchise,
        verbose_name='Franchise',
        related_name='jurisdictions',
        blank=True
    )
    name = models.CharField(
        "Jurisdiction name",
        max_length=255,
        db_index=True,
        unique=True,
    )
    phone_number = models.CharField(
        "Phone number",
        max_length=12,
        validators=[phone_number_regex],
        unique=True,
    )
  

Мой views.py

 class JurisdictionViewSet(viewsets.ModelViewSet):
    queryset = Jurisdiction.objects.all().prefetch_related('franchise')
    serializer_class = JurisdictionSerializer
  

serializers.py

 class JurisdictionSerializer(serializers.ModelSerializer):
    franchise = FranchiseSerializer(many=True)

    class Meta:
        model = Jurisdiction
        fields = (
            'id', 'name', 'phone_number', 'franchise',
        )
  

И сериализатор показывает мне:

 {
  "id": 1,
  "name": "Test juris 1",
  "phone_number": "200-000-1233",
   "franchise": [
      {
        "id": 1,
        "name": "Test franchise 1",
      },
      {
        "id": 2,
        "name": "Test franchise 2",
      }
}
  

Как я могу получить представление списка каждого отношения m2m как отдельного объекта в сериализаторе? Я попытался изменить метод to_representation сериализатора, но ничего не работает
ожидаемый результат:

 [
    {
      "id": 1,
      "name": "Test juris 1",
      "phone_number": "200-000-1233",
      "franchise_name": "Test franchise 1"
    },
    {
      "id": 1,
      "name": "Test juris 1",
      "phone_number": "200-000-1233",
      "franchise_name": "Test franchise 2"
    }
  ]
  

Ответ №1:

Вы можете настроить ListSerializer свой ModelSerializer . В частности, to_representation метод. Например:

 from rest_framework import serializers
class CustomJurisdictionListSerializer(serializers.ListSerializer):
    def to_representation(self, data):
        iterable = data.all() if isinstance(data, models.Manager) else data

        response = []
        
        for item in iterable:
            item_representation = self.child.to_representation(item)
            for franchise in item.franchise.all():
                representation = item_representation.copy()
                representation['franchise_name'] = franchise.name
                response.append(representation)
                
        return response
  

Затем удалите franchise JurisdictionSerializer и установите пользовательский сериализатор списка:

 class JurisdictionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Jurisdiction
        fields = (
            'id', 'name', 'phone_number',
        )
        list_serializer_class = CustomJurisdictionListSerializer
  

Комментарии:

1. Спасибо. Это работает. Вы знаете, как упорядочить по этому дополнительному полю?

2. Вы хотите упорядочить его по полю в Jurisdiction или в Franchise ?