No project description provided
Project description
geekie-wafer
Converts between object graphs represented by a dictionary and by models
Migrating from glibs.wafer
Most things just work by changing the import from glibs.wafer
to wafer
. The only exception is glibs.wafer.utils
was renamed to wafer.fields
.
Also the old glibs.utils.alias
has been moved to wafer.utils.alias
.
Usage
Suppose we have a very simple model serialized as follows:
serialized_presentation = {
"name": "Rockband Matches",
"author": "Edward Merryweather",
"type": "ppt",
}
We can map that to a model using Wafer as follows:
class Presentation(wafer.Model):
name = wafer.Field()
author = wafer.Field()
type = wafer.Field()
Converting the dictionary to a model then becomes very simple
presentation = Presentation(serialized_presentation)
print presentation.name # Outputs Rockband Matches
Going the other way around is also very straightforward
presentation = Presentation()
presentation.name = "Rockband Matches"
presentation.author = "Edward Merryweather"
presentation.serialize() # Outputs {
# "name": "Rockband Matches",
# "author": "Edward Merryweather"
# }
Note that fields whose value is None
are not written to the dictionary.
Embedded documents
Frequently models contain themselves other models:
friday_fun_event = {
"presentation": {
"name": "Rockband Matches",
},
}
For Wafer to properly serialize and deserialize this kind of object graph, you simply pass the model you want to use to the wafer.Field
constructor:
class Event(wafer.Model):
presentation = wafer.Field(Presentation)
event = Event(friday_fun_event)
event.presentation.name # Outputs "Rockband Matches"
And the other way around:
event = Event()
event.presentatiob # Outputs None
event.presentation = Presentation()
event.presentation.name = "Rockband Matches"
event.serialize() # Outputs the same as the friday_fun_event object
Embedded collections
In case your model contain a list of embedded models, you use the wafer.EmbeddedCollection
to declare the field
documents = {
"presentations": [{
"name": "Rockband Matches"
}, {
"name": "Other"
}]
}
class DocumentList(wafer.Model):
presentations = wafer.EmbeddedCollection(Presentation)
list = DocumentList(documents)
list.presentations[1].name # Outputs "Other"
Embedded collection fields are never set to None
, and wafer considers None
the same as an empty list. Because of that behavior, the following statements are true:
list = DocumentList()
list.presentations # Outputs []
list.serialize() # Outputs {}, empty list is ignored
Custom serialization/deserialization logic
If you have a field you want to map in some nonstandard way to its serialzed form, override serialize
and deserialize
methods
Customizing getters/setters
If you have a field whose getter/setter logic you want to customize, you'll find that the following doesn't work:
class Person(wafer.Model):
weight = wafer.Field()
@property
def weight(self): # Erases the old definition for 'weight'
return self.__weight
@weight.setter
def weight(self, value):
if value < 0:
raise ValueError()
self.__weight = value
In this situation, you can declare the field the following way:
class Person(wafer.Model):
__weight_field = wafer.Field()
# Rest of the code unaltered
And then everything will work as intended
person = Person({ "weight": -2 }) # raises ValueError
Polymorphism
Your model may have a collection of embedded documents of different types
class Phase(wafer.Model):
type = wafer.Field()
class VideoPhase(Phase):
video_url = wafer.Field()
class DrillPhase(Phase):
exercises = wafer.EmbeddedCollection(Exercise)
class Lecture(wafer.Model):
phases = wafer.EmbeddedCollection(Phase) # VideoPhase or DrillPhase
In such cases, serialization works out of the box but you'll find that deserialization doesn't as it always tries to convert the dictionary to a Phase
object, and the Phase
object doesn't know about the different fields each subclass has.
The solution is to use a custom deserialization logic, as follows:
class Phase(wafer.Model):
@staticmethod
def deserialize(obj):
if obj["type"] == "video":
return VideoPhase(obj)
else:
return DrillPhase(obj)
class Lecture(wafer.Model):
phases = wafer.EmbeddedCollection(Phase, deserializer=Phase.deserialize)
You may want to add logic to each subclass to ensure the type
field is correctly stored. Consider the following possibilities:
class VideoPhase(Phase):
def serialize(self):
obj = super(VideoPhase, self).serialize()
obj["type"] = "video"
return obj
class VideoPhase(Phase):
def __init__(self, *args, **kwargs):
super(VideoPhase, self).__init__(*args, **kwargs)
self.type = "video"
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for geekie_wafer-3.0.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c6a7a8bda0334ad8ef46c4a5b1d02da6be3407509e13cee27b8386f973282394 |
|
MD5 | 7ad722d3efdec16afb85288334a1c815 |
|
BLAKE2b-256 | 48af07e1d6fd41274f866260c3eed4e4340bedce0979f1e594ef35ed7d73b684 |