You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Graphene在Django查询响应中对OrderedDict排序?

问题

在Django应用中,我尝试通过Graphene的GenericScalar类型字段返回包含OrderedDict的字典。这些OrderedDict是按值排序的,但API响应里字典会被按键重新排序。

OrderedDict的结构为:{ id : [name, amount] }

发送的OrderedDict示例:

{ 'foods': {
    3: ['apple', 5],
    1: ['banana', 7],
    2: ['carrot', 3]
  }, 
  'animals': {
    5: ['cat', 3],
    3: ['dog', 10],
    1: ['pig', 5],
  }
}

API返回的响应:

{ 'foods': {
    1: ['banana', 7],
    2: ['carrot', 3],
    3: ['apple', 5],
  }, 
  'animals': {
    1: ['pig', 5],
    3: ['dog', 10],
    5: ['cat', 3],
  }
}

我特意使用OrderedDict来保留顺序,但始终找不到阻止Graphene按键重排的方法。

我的ObjectType和Query定义如下:

class DashboardType(g.ObjectType):
    data = GenericScalar()

class Query(object):
    dashboard = Field(DashboardDataType, id=ID(), date=Date())
   
    def resolve_dashboard(self, info, **kwargs):
        data = function_to_get_the_data(kwargs)
        # 到这一步数据排序都是正确的
        return data

直到Graphene发送响应前,数据顺序都符合预期,但响应中顺序丢失了,请问如何实现保留原有顺序?

解决方案

方法1:改用列表嵌套字典替代OrderedDict

JSON规范中对象是无序的,Graphene在序列化时会自动将OrderedDict转换为普通字典,导致顺序丢失。最稳妥的处理方式是将需要保留顺序的结构调整为列表嵌套字典,通过列表明确传递顺序:

调整后的数据结构:

{
    'foods': [
        {'id': 3, 'name': 'apple', 'amount': 5},
        {'id': 1, 'name': 'banana', 'amount': 7},
        {'id': 2, 'name': 'carrot', 'amount': 3}
    ],
    'animals': [
        {'id': 5, 'name': 'cat', 'amount': 3},
        {'id': 3, 'name': 'dog', 'amount': 10},
        {'id': 1, 'name': 'pig', 'amount': 5}
    ]
}

这种方式下,Graphene序列化时会完整保留列表的顺序,前端也能直接按顺序处理数据。

方法2:自定义Scalar类型处理OrderedDict

如果必须保留字典结构,可以自定义一个能识别OrderedDict并保留顺序的Scalar类型:

from graphene.types.scalars import Scalar
from graphql.language import ast
import json
from collections import OrderedDict

class OrderedDictScalar(Scalar):
    @staticmethod
    def serialize(value):
        # 对OrderedDict使用sort_keys=False参数序列化,避免按键排序
        if isinstance(value, OrderedDict):
            return json.loads(json.dumps(value, sort_keys=False))
        # 其他类型按默认逻辑处理
        return value

    @staticmethod
    def parse_literal(node):
        if isinstance(node, ast.StringValue):
            return json.loads(node.value)
        return None

    @staticmethod
    def parse_value(value):
        return value

之后在ObjectType中替换原有的GenericScalar为这个自定义类型:

class DashboardType(g.ObjectType):
    data = OrderedDictScalar()

方法3:重写GenericScalar的序列化逻辑

Graphene的GenericScalar在处理字典时会默认转换为普通dict,导致顺序丢失。可以继承GenericScalar并重写序列化方法:

from graphene.types.generic import GenericScalar
from collections import OrderedDict

class OrderedGenericScalar(GenericScalar):
    @staticmethod
    def serialize(value):
        if isinstance(value, OrderedDict):
            # 直接返回OrderedDict,跳过默认的普通dict转换
            return value
        return super().serialize(value)

然后将DashboardType中的data字段类型替换为OrderedGenericScalar即可。

内容的提问来源于stack exchange,提问作者Laura Montes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:32:41