python-3.xdjangographqlgraphene-python

How to avoid Graphene sorting an OrderedDict on query response? (Python, Django)


I am trying to return a dict of OrderedDicts from a Graphene endpoint in a Django application, by using the GenericScalar type field. The OrderedDicts are sorted based on value, but the API seems to re-sort the dicts by key.

The OrderedDicts items format is: { id : [name, amount] }

Example of one of the OrderedDicts that I send:

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

What is received in the endpoint response:

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

I am specifically using OrderedDicts because the order is important, but I have not found a way of avoiding Graphene to re-sort the OrderedDicts by key.

This is the how the ObjectType and Query are declared, althought is is nothing out of the ordinary.

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)
        # up until this point the data is still sorted correctly
        return data

The data is sorted as expected up until the response is sent by the Graphene API. I would expect the order to be mantained, but it is not.

Any suggestions on how to achieve this? I didn't think it would be so difficult, but I am out of ideas.


Solution

  • I would suggest as a model:

    type Thing {
      id: ID!
      name: String!
      subthings: [Subthing]
    }
    
    type Subthing {
      id: ID!
      name: String!
      amount: Int
    }
    

    Then you could have a guery:

    query getThings(orderBy: String, direction: String): [Thing]
    

    And against that you could execute:

    query getThingsOrderByName($orderBy: 'name', $direction: 'asc') {
      query getThings(orderBy: $orderBy, direction: $direction) {
        id
        name
        subthings {
          id
          name
          amount
        }
      }
    }
    

    Your subThings resolver could then sort the subThings based on the orderBy and 'direction' query parameters.

    Your return object would then look like:

    [
      {
        "id": `
        "name": "foods"
        "subthings": [
          {
            "id": 3,
            "name": "apple",
            "amount": 5,
          },
          etc…
        ]
      }
    ]