Django 2 – Rest Framework: Relação um para Muitos (1:N)

Logotipo Python

Como fazer, em sua API, para exibir os dados de algum relacionamento? Essa é a pergunta que me fiz há um tempo atrás. Imagine que você tenha uma API que retorne Ordens de Serviço (ORDENS) e que essas ORDENS possuem vários apontamentos de hora, que chamaremos de LOG. Como fazer para que, em cada Ordem, sejam retornados todos os Logs?

O que queremos, é exibir algo assim:

A imagem mostra um Objeto JSON retornando os dados de log dentro dos dados da Ordem

PRIMEIRO PASSO: MODELS

class MaintenanceOrder(models.Model):
    order_code = models.CharField(max_length=12, null=True)
    note_code = models.CharField(max_length=12, null=True)
    equipment = models.CharField(max_length=18, null=True)
    locale = models.CharField(max_length=30, null=True)
    short_description = models.CharField(max_length=40, null=False)
    description = models.TextField(null=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.order_code

    class Meta:
        managed = True


class MaintenanceLog(models.Model):
    maintenance_order = models.ForeignKey(MaintenanceOrder, on_delete=models.DO_NOTHING)

    start_time = models.DateTimeField()
    stop_time = models.DateTimeField(null=True)

    description = models.TextField(null=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.description

    class Meta:
        managed = True

SEGUNDO PASSO: SERIALIZERS

Você deverá criar agora dois Serializers em um arquivo chamado serializers.py.

class MaintenanceLogSerializer(serializers.ModelSerializer):
    class Meta:
        model = MaintenanceLog
        fields = '__all__'


class MaintenanceOrderSerializer(serializers.ModelSerializer):
    status_code = serializers.IntegerField(source='status.status_code', read_only=True)
    order_log = MaintenanceLogSerializer(source='maintenancelog_set', many=True, read_only=True)

    class Meta:
        model = MaintenanceOrder
        fields = ('id', 'order_code', 'note_code',
                  'equipment', 'locale',
                  'short_description', 'description',
                  'created_at', 'updated_at',
                  'order_log')

O segredo está na classe MaintenanceOrderSerializer, na variável order_log. Nessa variável, setamos o MaintenanceLogSerializer e setamos que a fonte dele é uma chave estrangeira.

Nesse timo de relacionamento (1 x N), temos que especificar todos os campos que queremos exibir. Não podemos setar ‘__all__’.

TERCEIRO PASSO: VIEW

@api_view(['GET'])
def orders(request):
    try:
        orders = MaintenanceOrder.objects.all()
        results = MaintenanceOrderSerializer(orders, many=True).data
        return Response({
            'response': 'success',
            'data': results
        }, status=status.HTTP_200_OK)
    except MaintenanceOrder.DoesNotExist:
        return Response(data={'response': 'null'}, status=status.HTTP_204_NO_CONTENT)

QUARTO PASSO: URL (rotas)

Agora basta criar sua rota. Veja um exemplo:

path('api/v1/orders', api.orders, name='meuapp.orders'), ...

RESULTADO

O resultado deverá ser algo como:

{
        {
            "id": 86,
            "order_code": "000310016530",
            "note_code": "",
            "equipment": "000000000050002836",
            "locale": "CF10-431-ND",
            "short_description": "Bomba parada",
            "description": null,
            "created_at": "2018-09-17T13:40:10.697260",
            "updated_at": "2018-09-17T13:40:10.697277",
            "order_log": []
        },
        {
            "id": 100,
            "order_code": null,
            "note_code": null,
            "equipment": "86754",
            "locale": "MP10-642-INF",
            "short_description": "Mais um teste!",
            "description": "",
            "created_at": "2018-09-18T15:45:57.172669",
            "updated_at": "2018-09-18T15:46:17.445052",
            "order_log": [
                {
                    "id": 41,
                    "start_time": "2018-09-18T15:45:59.214199",
                    "stop_time": "2018-09-18T15:46:03.627028",
                    "description": "Ordem pausada.",
                    "created_at": "2018-09-18T15:45:59.214911",
                    "updated_at": "2018-09-18T15:46:03.628129",
                    "maintenance_order": 100,
                },
                {
                    "id": 42,
                    "start_time": "2018-09-18T15:46:06.134436",
                    "stop_time": "2018-09-18T15:46:17.459454",
                    "description": "Ordem pausada.",
                    "created_at": "2018-09-18T15:46:06.135495",
                    "updated_at": "2018-09-18T15:46:17.460069",
                    "maintenance_order": 100
                }
            ]
        }
}

Espero que tenha ajudado como fui ajudado.

Mais detalhes podem ser vistos nessa dúvida que havia lançado no StackOverflow.

https://stackoverflow.com/questions/52447984/django-rest-framework-one-to-many-relationship-not-working/52449174#52449174

CategoriasSem categoria

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.