117 lines
3.4 KiB
ReStructuredText
117 lines
3.4 KiB
ReStructuredText
.. _manipulating_data_structures:
|
|
|
|
Manipulating Data Structures
|
|
============================
|
|
|
|
Colander schemas have some utility functions which can be used to manipulate
|
|
an :term:`appstruct` or a :term:`cstruct`. Nested data structures can be
|
|
flattened into a single dictionary or a single flattened dictionary can be used
|
|
to produce a nested data structure. Values of particular nodes can also be set
|
|
or retrieved based on a flattened path spec.
|
|
|
|
Flattening a Data Structure
|
|
---------------------------
|
|
|
|
:meth:`colander.SchemaNode.flatten` can be used to convert a datastructure with
|
|
nested dictionaries and/or lists into a single flattened dictionary where each
|
|
key in the dictionary is a dotted name path to the node in the nested structure.
|
|
|
|
Consider the following schema:
|
|
|
|
.. code-block:: python
|
|
:linenos:
|
|
|
|
import colander
|
|
|
|
class Friend(colander.TupleSchema):
|
|
rank = colander.SchemaNode(colander.Int(),
|
|
validator=colander.Range(0, 9999))
|
|
name = colander.SchemaNode(colander.String())
|
|
|
|
class Phone(colander.MappingSchema):
|
|
location = colander.SchemaNode(colander.String(),
|
|
validator=colander.OneOf(['home', 'work']))
|
|
number = colander.SchemaNode(colander.String())
|
|
|
|
class Friends(colander.SequenceSchema):
|
|
friend = Friend()
|
|
|
|
class Phones(colander.SequenceSchema):
|
|
phone = Phone()
|
|
|
|
class Person(colander.MappingSchema):
|
|
name = colander.SchemaNode(colander.String())
|
|
age = colander.SchemaNode(colander.Int(),
|
|
validator=colander.Range(0, 200))
|
|
friends = Friends()
|
|
phones = Phones()
|
|
|
|
Consider also a particular serialization of data using that schema:
|
|
|
|
.. code-block:: python
|
|
:linenos:
|
|
|
|
appstruct = {
|
|
'name':'keith',
|
|
'age':20,
|
|
'friends':[(1, 'jim'),(2, 'bob'), (3, 'joe'), (4, 'fred')],
|
|
'phones':[{'location':'home', 'number':'555-1212'},
|
|
{'location':'work', 'number':'555-8989'},],
|
|
}
|
|
|
|
This data can be flattened:
|
|
|
|
.. code-block:: python
|
|
:linenos:
|
|
|
|
schema = Person()
|
|
fstruct = schema.flatten(appstruct)
|
|
|
|
The resulting flattened structure would look like this:
|
|
|
|
.. code-block:: python
|
|
:linenos:
|
|
|
|
{
|
|
'name': 'keith',
|
|
'age': 20,
|
|
'friends.0.rank': 1,
|
|
'friends.0.name': 'jim',
|
|
'friends.1.rank': 2,
|
|
'friends.1.name': 'bob',
|
|
'friends.2.rank': 3,
|
|
'friends.2.name': 'joe',
|
|
'friends.3.rank': 4,
|
|
'friends.3.name': 'fred',
|
|
'phones.0.location': 'home',
|
|
'phones.0.number': '555-1212',
|
|
'phones.1.location': 'work',
|
|
'phones.1.number': '555-8989',
|
|
}
|
|
|
|
The process can be reversed using :meth:`colandar.SchemaNode.unflatten`:
|
|
|
|
.. code-block:: python
|
|
:linenos:
|
|
|
|
appstruct = schema.unflatten(fstruct)
|
|
|
|
Either an :term:`appstruct` or a :term:`cstruct` can be flattened or unflattened
|
|
in this way.
|
|
|
|
Accessing and Mutating Nodes in a Data Structure
|
|
------------------------------------------------
|
|
|
|
:attr:`colander.SchemaNode.get_value` and :attr:`colander.SchemaNode.set_value`
|
|
can be used to access and mutate nodes in an :term:`appstruct` or
|
|
:term:`cstruct`. Using the example from above:
|
|
|
|
.. code-block:: python
|
|
:linenos:
|
|
|
|
# How much do I like Joe?
|
|
rank = schema.get_value(appstruct, 'friends.2.rank')
|
|
|
|
# Joe bought me beer. Let's promote Joe.
|
|
schema.set_value(appstruct, 'friends.2.rank', rank + 5000)
|