Django Rest Framework - группирует данные по динамическому ключу - PullRequest
0 голосов
/ 20 сентября 2019

Я пытаюсь отформатировать данные при запросе моего API.Я могу получить мои данные так:

"results": [
        {
            "Cat1": [
                {
                    "job": String,
                    "position": Integer
                }
            ]
        },
        {
            "Cat1": [
                {
                    "job": String,
                    "position": Integer
                }
            ]
        },
        {
            "Cat2": [
                {
                    "job": String,
                    "position": Integer
                }
            ]
        }
    ]

Но я хочу что-то вроде этого:

"results": [
        {
            "Cat1": [
                {
                    "job": String,
                    "position": Integer
                },
                {
                    "job": String,
                    "position": Integer
                }
            ]
        },
        {
            "Cat2": [
                {
                    "job": String,
                    "position": Integer
                }
            ]
        }
    ]

Я использую такой сериализатор:

class CustomSerializer(serializers.ModelSerializer):
    category = CatSerializer()
    job = JobSerializer()

    class Meta:
        model = MyModel
        fields = '__all__'

    def to_representation(self, value):
        return {
            value.category.name: [{"job": value.job.name,
                                 "position": value.position, }]

cat1и cat2 - динамика, они из другой таблицы.Я не понимаю, как правильно создавать свои массивы с использованием этих сериализаторов.Категория - это поле @Property в моей модели, который является внешним ключом задания.

Мои модели:

class MyModel(models.Model):
    CHOICES = [(i, i) for i in range(4)]

    partner = models.ForeignKey(Partner, on_delete=models.CASCADE)
    job = models.ForeignKey(
        Job, on_delete=models.CASCADE)
    position = models.IntegerField(choices=CHOICES)

    @property
    def category(self):
        return self.job.category.domain


    def __str__(self):
        return '%s | %s | %s | position: %s' % (self.partner.name, self.domain.name, self.job.name, self.position)
class Job(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    code = models.CharField(
        max_length=255, unique=True)
    name = models.CharField(
        max_length=255)
class Category(models.Model):
    domain = models.ForeignKey(Domain, on_delete=models.CASCADE)
    code = models.CharField(
        max_length=5)
    name = models.CharField(max_length=255)
    hourly_rate = models.FloatField(
        null=True, blank=True)

Как мне работать с сериализаторами для форматированиямои данные правильно?

РЕДАКТИРОВАТЬ:

Я закончил что-то подобное, за исключением ListSerializer.

Я использовал 2 ModelSerilizer

class MyModelCustomSerializer(serializers.ModelSerializer):
    position = serializers.IntegerField(read_only=True)
    job = serializers.CharField(source='job.name', read_only=True)

    class Meta:
        model = MyModel
        fields = ['job', 'position']

    def to_representation(self, value):
        return {"position": value.position,
                "job": {"name": value.job.name, "slug": value.job.slug, 
             "title": value.job.seo_title}
                }

И

class CategoryCustomSerializer(serializers.ModelSerializer):
    models = MyModelustomerSerializer(many=True)

    class Meta:
        model = Category
        fields = ['category', 'MyModel']

    def to_representation(self, value):

        filters = {'job__category__domain__name': value.name}

        myModels = MyModel.objects.filter(**filters)
        serializer = MyModelCustomSerializer(instance=myModels, many=True,)

        return {value.name: serializer.data}

Но если я попытаюсь использовать jobSerializer, который уже существует вместо

"job": {"name": value.job.name, "slug": value.job.slug, "title": value.job.seo_title} },

, я получаю эту ошибку: Объект типа 'Job'не JSON-сериализуемый, но все равно работает, потому что мне не нужны все поля

1 Ответ

0 голосов
/ 24 сентября 2019

Я бы пошёл в направлении реализации пользовательского ListSerializer для ModelSerializer и переопределения его to_representation метода.

from rest_framework import serializers
from collections import OrderedDict

class CustomListSerializer(serializers.ListSerializer):
    def to_representation(self, data):
        iterable = data.all() if isinstance(data, models.Manager) else data
        list_rep = OrderedDict()

        for item in iterable:
            child_rep = self.child.to_representation(item)
            k, v = list(child_rep.items()).pop()
            list_rep.setdefault(k, []).append(v)

        return [
            {k: v} 
            for k, v in list_rep.items()
        ]

Затем настройте модель Meta для его использования

class CustomSerializer(serializers.ModelSerializer):
    category = CatSerializer()
    job = JobSerializer()

    class Meta:
        model = MyModel
        fields = '__all__'
        list_serializer_class = CustomListSerializer

    def to_representation(self, value):
        return {
            value.category.name: [{"job": value.job.name,
                                 "position": value.position, }]
...