【问题标题】:Django Rest Framework - Group data by dynamic KeyDjango Rest Framework - 按动态键对数据进行分组
【发布时间】:2019-09-20 14:41:56
【问题描述】:

我在查询我的 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 可序列化的,但它仍然可以工作,因为我不需要所有字段

【问题讨论】:

  • 请展示您的模型或至少它们之间的关系(MyModel、Category 和 Job)。但是你的序列化器是针对 MyModel 的,所以很明显它会返回一个 MyModel 实例列表。
  • 您可能应该从 Category 序列化程序开始,与位置有嵌套关系,因为您希望以类别列表(而不是位置)结束。

标签: django django-rest-framework


【解决方案1】:

我会朝着为 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, }]

【讨论】:

  • 我以这样的代码结束,除了 ListSerializer
猜你喜欢
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2015-06-23
  • 1970-01-01
  • 2022-12-09
  • 2021-06-25
  • 2019-03-23
相关资源
最近更新 更多