In todays episode we will use Colander with validators for nested elements :) Checkout my experience with them.
This episode is a series about colander
S0-E8/E30 :)
Colander Nested
Let's say you have a nested list elements that also have atributes like this :
{
"users": [
{
"id": "1",
"name": "Anselmos",
},
{
"id": "1",
"name": "Somlesna",
}
],
"list_name": "name_of_users"
}
Code that I would typically create would look like this:
import json
dict_1 = {
"users": [
{
"id": "1",
"name": "Anselmos",
},
{
"id": "1",
"name": "Somlesna",
}
],
"list_name": "name_of_users"
}
api_data = json.dumps(dict_1)
print api_data
json_loaded = json.loads(api_data)
dicted = dict(json_loaded)
print dicted
class JsonDeserialize:
def __init__(self, **entry):
self.__dict__.update(entry)
classed = JsonDeserialize(**dicted)
print classed.users
print classed.users[0]
What is the problem with it ? Well you still have to manually create a validator for each user
list-element.
Colander can fix that with:
import json
import colander
dict_1 = {
"users": [
{
"id": "1",
"name": "Anselmos",
},
{
"id": "1",
"name": "Somlesna",
}
],
"list_name": "name_of_users"
}
api_data = json.dumps(dict_1)
print api_data
json_loaded = json.loads(api_data)
dicted = dict(json_loaded)
print dicted
class User(colander.MappingSchema):
id = colander.SchemaNode(colander.Int())
name = colander.SchemaNode(colander.String())
class Users(colander.SequenceSchema):
user = User()
class Data(colander.MappingSchema):
users = Users()
list_name = colander.SchemaNode(colander.String())
serialized= Data().serialize(dicted)
import pprint
print pprint.pformat(serialized)
deserialized = Data().deserialize(dicted)
print pprint.pformat(deserialized)
Now I now this looks pretty simple. But let's make another example that will use validator - which you could not create with simple json and dict "hack" :
import json
import colander
dict_1 = {
"users": [
{
"id": "1",
"name": "Anselmos",
},
{
"id": "1",
"name": "Somlesna",
}
],
"list_name": "name_of_users"
}
api_data = json.dumps(dict_1)
print api_data
json_loaded = json.loads(api_data)
dicted = dict(json_loaded)
print dicted
class User(colander.MappingSchema):
id = colander.SchemaNode(colander.Int(), validator=colander.NoneOf([1]))
name = colander.SchemaNode(colander.String())
class Users(colander.SequenceSchema):
user = User()
class Data(colander.MappingSchema):
users = Users()
list_name = colander.SchemaNode(colander.String())
serialized= Data().serialize(dicted)
import pprint
print pprint.pformat(serialized)
deserialized = Data().deserialize(dicted)
print pprint.pformat(deserialized)
Oh ... now it will fail with :
local/lib/python2.7/site-packages/colander/__init__.py", line 704, in _impl
raise error
colander.Invalid: {'users.0.id': u'"1" must not be one of 1',
'users.1.id': u'"1" must not be one of 1'}
Because we added to our schema validator like that:
id = colander.SchemaNode(colander.Int(), validator=colander.NoneOf([1]))
Ofcourse the obvious fix for that will be to change id's for user's to different than 1.
Colander build-in validators
There are 13 build-in colander validators that we can make great use.
I encourage you to try them :)
1. colander.All(*validators)
2. colander.Any(*validators)
3. colander.Range(min=None, max=None, min_err='${val} is less than minimum value ${min}', max_err='${val} is greater than maximum value ${max}')
4. colander.Length(min=None, max=None, min_err='Shorter than minimum length ${min}', max_err='Longer than maximum length ${max}')
5. colander.OneOf(choices)
6. colander.NoneOf(choices, msg_err='"${val}" must not be one of ${choices}')
7. colander.ContainsOnly(choices)
8. colander.Function(function, msg=None, message=None)
9. colander.Regex(regex, msg=None, flags=0)
10. colander.Email(msg=None)
11. colander.luhnok(node, value)
12. colander.url
13. colander.uuid
Acknowledgements
Thanks!
That's it :) Comment, share or don't :)
If you have any suggestions what I should blog about in the next articles - please give me a hint :)
BTW - today is the last day when I eat junk food - why ? Because I'm starting another challenge for not eating junk food for the time of fasting
- so at least 40 days :) - So Keep finger crossed for me :)
See you tomorrow! Cheers!
Comments
comments powered by Disqus