Django Rest Framework-通过动态键对数据进行分组

时间:2019-09-20 14:41:56

标签: django django-rest-framework

查询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个ModelSerilizers

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 :(得分:0)

我将朝为ModelSerializer实现自定义ListSerializer并覆盖其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, }]