首页 > 解决方案 > 具有一对多唯一值的 Django Rest Framework 嵌套序列化程序

问题描述

我有一个用于状态的模型和一个用于为每种状态存储多种语言的模型:

class Status(models.Model):
    code = models.IntegerField()

class StatusValueLang(models.Model):
    status = models.ForeignKey(Status, related_name="langs", on_delete=models.CASCADE)
    lang = models.CharField(max_length=3)       
    value = models.CharField(max_length=255)

我有一个模型使用状态

class Order(models.Model):
    number = models.CharField(max_length=10)
    status = models.ForeignKey(Status, on_delete=models.PROTECT)

然后,我想序列化这个查询集(获取带有英文状态名称的订单):

orders = Order.objects.filter(status__langs__lang='en')

使用序列化器。序列化器:

class StatusValueLangSerializer(serializers.Serializer):
    value = serializers.CharField(max_length=255)

class StatusSerializer(serializers.Serializer):
    langs = StatusValueLangSerializer(many=True)

class OrderSerializer(serializers.Serializer):
    number = models.CharField(max_length=10)
    status = StatusSerializer()

它可以工作,但是由于'langs = StatusValueLangSerializer(many = True)'行中的'Many = True',尽管我的过滤器(status__langs__lang ='en'),StatusSerializer仍返回所有行(语言)我如何设置序列化程序以获得此结果:

[
    {
        "number": "123",
        "status": {
            "langs": [
                {
                    "value" : "Approved" <-- Just one, filtered row. 
                }
            ]
        }
    }
]

或者可能更好:

[
    {
        "number": "123",
        "status": {
            "value": "Approved"
        }
    }
]

标签: djangodjango-rest-framework

解决方案


这与序列化程序无关。这是关于查询本身。如果您在模型上查询,将返回对象Order的 QuerySet 。Order

假设有一个名为 的订单对象foo。这foo有一个状态,它的状态有很多语言。那么您对查询的期望是什么?

您在问题中提到的查询:Order.objects.filter(status__langs__lang='en')说给我所有Orders 他们的状态至少包含一个 s lang='en'。订单序列化程序包含状态序列化程序,状态序列化程序包含其所有语言。

为了在序列化对象中显示一种特定语言,您应该自定义序列化程序。像这样的东西:

>>> class NewOrderSerializer(serializers.Serializer):
...     number = serializers.CharField(max_length=10)
...
>>> desired_lang = 'en'
>>> desired_lang_value = StatusValueLang.objects.get(lang='en').value
>>> orders = Order.objects.filter(status__langs__lang=desired_lang)
>>> seriliazed_orders = NewOrderSerializer(orders, many=True)
>>> for order in seriliazed_orders:
...     order['status'] = {'value': desired_lang}
...
>>> print(json.dumps(s, indent=4, sort_keys=True))
[
    {
        "number": "10001",
        "status": {
            "value": desired_lang_value
        }
    }
]
>>>

但这不是一个好方法;这只是一个简单的方法。


推荐阅读