Models¶
Base¶
-
class
sheraf.models.base.
BaseModel
¶ Bases:
object
BaseModel
is the base class for every other model classes. This is where the attribute reading and writing are handled.Models can be used as dictionaries:
>>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute() ... >>> with sheraf.connection(): ... dict(Cowboy.create(name="George Abitbol")) {'name': 'George Abitbol', '_creation': ...}
-
assign
(**kwargs)¶ Takes an arbitrary number of keywords arguments, and updates the model attributes matching the arguments.
This functions recursively calls
sheraf.attributes.base.BaseAttribute.edit()
with addition, edition and deletion to True.>>> class Arm(sheraf.InlineModel): ... name = sheraf.SimpleAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "people" ... name = sheraf.SimpleAttribute() ... arms = sheraf.SmallListAttribute(sheraf.InlineModelAttribute(Arm)) ... >>> with sheraf.connection(commit=True): ... george = Cowboy.create(name="Three arms cowboy", arms=[ ... {"name": "Arm 1"}, {"name": "Arm 2"}, {"name": "Arm 3"}, ... ]) ... len(george.arms) 3 >>> with sheraf.connection(commit=True): ... george.assign(name="George Abitbol", arms=[ ... {"name": "Superarm 1"}, {"name": "Superarm 2"}, ... ]) ... len(george.arms) 2 >>> with sheraf.connection(): ... george.arms[0].name 'Superarm 1'
George passed from 3 arms to only 2 because assign does remove sub models. If we had called
update()
instead, George would have his two first arms be renamed superarms but, the third one would not have been removed.
-
copy
(**kwargs)¶ - Parameters
**kwargs – Keywords arguments will be passed to
create()
and thus wont be copied.- Returns
a copy of this instance.
-
classmethod
create
(default=None, *args, **kwargs)¶ Create a model instance.
- Parameters
default – The data structure that will be used to store the model state.
**kwargs – Any model attribute can be initialized with the matching keyword.
- Returns
The newly created model.
>>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute(default="John Doe") ... >>> with sheraf.connection(commit=True): ... cowboy = Cowboy.create() ... assert "John Doe" == cowboy.name ... ... cowboy = Cowboy.create(name="George Abitbol") ... assert "George Abitbol" == cowboy.name ... ... Cowboy.create(this_attribute_does_not_exist="something") # raises a TypeError Traceback (most recent call last): ... TypeError: TypeError: create() got an unexpected keyword argument 'this_attribute_does_not_exist'
The function can also create sub-models recursively:
>>> class Horse(sheraf.InlineModel): ... name = sheraf.SimpleAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute(default="John Doe") ... horse = sheraf.InlineModelAttribute(Horse) ... >>> with sheraf.connection(): ... cowboy = Cowboy.create(name="George Abitbol", horse={"name": "Jolly Jumper"}) ... cowboy.horse.name 'Jolly Jumper'
-
default_mapping
¶ alias of
sheraf.types.SmallDict
-
edit
(value, addition=True, edition=True, deletion=False, replacement=False)¶ Take a dictionary and a set of options, and try to applies the dictionary values to the model structure.
- Parameters
value – The dictionary containing the values. The dictionary elements that do not match the model attributes will be ignored.
addition – If True, elements present in value and absent from the model attributes will be added.
edition – If True, elements present in both value and the model will be updated.
deletion – If True, elements present in the model and absent from value will be deleted.
replacement – Like edition, but create a new element instead of updating one.
-
keys
()¶ - Returns
The model attribute names.
-
reset
(attribute)¶ Resets an attribute to its default value.
-
update
(**kwargs)¶ Takes an arbitrary number of keywords arguments, and updates the model attributes matching the arguments.
This functions recursively calls
sheraf.attributes.base.BaseAttribute.edit()
with addition and edition to True.>>> class Horse(sheraf.InlineModel): ... name = sheraf.SimpleAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "people" ... name = sheraf.SimpleAttribute() ... horse = sheraf.InlineModelAttribute(Horse) ... >>> with sheraf.connection(commit=True): ... george = Cowboy.create(name="George", horse={"name": "Centaurus"}) ... george.update(name="*incognito*", horse={"name": "Jolly Jumper"}) ... george.name '*incognito*' >>> with sheraf.connection(): ... george.horse.name 'Jolly Jumper'
Note that sub-models are also edited.
-
Indexation mechanism¶
-
class
sheraf.models.indexation.
BaseIndexedModel
¶ Bases:
sheraf.models.base.BaseModel
This class handles the whole indexation mechanism. The mechanisms for reading or iterating over models in the database are handled here.
-
copy
(**kwargs)¶ Copies a model. The attributes carrying an unique index wont be copied, they will be resetted instead.
- Parameters
**kwargs – Keywords arguments will be passed to
create()
and thus wont be copied.- Returns
a copy of this instance.
-
classmethod
create
(*args, **kwargs)¶ Create a model instance.
- Parameters
default – The data structure that will be used to store the model state.
**kwargs – Any model attribute can be initialized with the matching keyword.
- Returns
The newly created model.
>>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute(default="John Doe") ... >>> with sheraf.connection(commit=True): ... cowboy = Cowboy.create() ... assert "John Doe" == cowboy.name ... ... cowboy = Cowboy.create(name="George Abitbol") ... assert "George Abitbol" == cowboy.name ... ... Cowboy.create(this_attribute_does_not_exist="something") # raises a TypeError Traceback (most recent call last): ... TypeError: TypeError: create() got an unexpected keyword argument 'this_attribute_does_not_exist'
The function can also create sub-models recursively:
>>> class Horse(sheraf.InlineModel): ... name = sheraf.SimpleAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute(default="John Doe") ... horse = sheraf.InlineModelAttribute(Horse) ... >>> with sheraf.connection(): ... cowboy = Cowboy.create(name="George Abitbol", horse={"name": "Jolly Jumper"}) ... cowboy.horse.name 'Jolly Jumper'
-
delete
()¶ Delete the current model instance.
>>> class MyModel(sheraf.Model): ... table = "my_model" ... >>> with sheraf.connection(): ... m = MyModel.create() ... assert m == MyModel.read(m.id) ... m.delete() ... m.read(m.id) Traceback (most recent call last): ... sheraf.exceptions.ModelObjectNotFoundException: Id '...' not found in MyModel
-
classmethod
filter
(predicate=None, **kwargs)¶ Shortcut for
sheraf.queryset.QuerySet.filter()
.- Returns
-
classmethod
get
(*args, **kwargs)¶ Shortcut for
sheraf.queryset.QuerySet.filter()
andsheraf.queryset.QuerySet.get()
.Cowboy.get(name="Peter")
andCowboy.filter(name="Peter").get()
are equivalent.- Returns
The instance of the model if the filter matches exactly one instance. Otherwise, it raises a
QuerySetUnpackException
.
>>> class Cowboy(sheraf.Model): ... table = "people" ... name = sheraf.SimpleAttribute() ... age = sheraf.SimpleAttribute() ... >>> with sheraf.connection(commit=True): ... peter = Cowboy.create(name="Peter", age=30) ... steven = Cowboy.create(name="Steven", age=30) ... assert peter == Cowboy.get(name="Peter") ... >>> with sheraf.connection(): ... Cowboy.get() Traceback (most recent call last): ... sheraf.exceptions.QuerySetUnpackException: Trying to unpack more than 1 value from a QuerySet >>> with sheraf.connection(): ... Cowboy.get(age=30) Traceback (most recent call last): ... sheraf.exceptions.QuerySetUnpackException: Trying to unpack more than 1 value from a QuerySet >>> with sheraf.connection(): ... Cowboy.get(name="Unknown cowboy") Traceback (most recent call last): ... sheraf.exceptions.EmptyQuerySetUnpackException: Trying to unpack an empty QuerySet
-
property
identifier
¶ The identifier is the value of the primary_key for the current instance. If the primary_key is ‘id’, then the identifier might be an UUID.
-
classmethod
index_table_rebuild
(index_names=None)¶ Resets a model indexation tables.
This method should be called if an attribute became indexed in an already populated database.
- Parameters
index_names – A list of index names to reset. If None, all the indexes will be reseted. The primary index cannot be resetted.
-
classmethod
order
(*args, **kwargs)¶ Shortcut for
sheraf.queryset.QuerySet.order()
.- Returns
-
classmethod
read
(*args, **kwargs)¶ Get a model instance from its identifier. If the model identifier is not valid, a
ModelObjectNotFoundException
is raised.The function takes only one parameter which key is the index where to search, and which value is the index identifier. If the index is multiple, a
MultipleIndexException
is raised. By default the index used is the id index.- Parameters
args – The
identifier
of the model. There can be only one positionnal or keyword argument.kwargs – The
identifier
of the model. There can be only one positionnal or keyword argument.
- Returns
The
BaseIndexedModel
matching the id.
>>> class MyModel(sheraf.Model): ... table = "my_model" ... unique = sheraf.SimpleAttribute().index(unique=True) ... multiple = sheraf.SimpleAttribute().index() ... >>> with sheraf.connection(): ... m = MyModel.create(unique="A", multiple="B") ... assert MyModel.read(m.id) == m ... assert MyModel.read(unique="A") == m ... >>> with sheraf.connection(): ... MyModel.read("invalid") Traceback (most recent call last): ... ModelObjectNotFoundException >>> with sheraf.connection(): ... MyModel.read(multiple="B") Traceback (most recent call last): ... MultipleIndexException
-
classmethod
read_these
(*args, **kwargs)¶ Get model instances from their identifiers. Unlike
read_these()
,If an instance identifiers does not exist, aModelObjectNotFoundException
is raised.The function takes only one parameter which key is the index where to search, and which values are the index identifier. By default the index used is the id index.
- Returns
A generator over the models matching the keys.
>>> class MyModel(sheraf.IntIndexedNamedAttributesModel): ... table = "my_model" ... >>> with sheraf.connection(): ... m1 = MyModel.create(id=1) ... m2 = MyModel.create(id=2) ... ... assert [m1, m2] == list(MyModel.read_these([m1.id, m2.id])) ... list(MyModel.read_these(["invalid"])) Traceback (most recent call last): ... sheraf.exceptions.ModelObjectNotFoundException: Id 'invalid' not found in MyModel, 'id' index
-
classmethod
read_these_valid
(*args, **kwargs)¶ Return model instances from an index. Unlike
read_these()
, invalid index values are ignored.The function takes only one parameter which key is the index where to search, and which values are the index identifier. By default the index used is the id index.
- Returns
A generator over the models matching the keys.
>>> class MyModel(sheraf.IntIndexedNamedAttributesModel): ... table = "my_model" ... >>> with sheraf.connection(): ... m1 = MyModel.create(id=1) ... m2 = MyModel.create(id=2) ... ... assert [m1, m2] == list(MyModel.read_these_valid([m1.id, m2.id])) ... assert [m1, m2] == list(MyModel.read_these_valid([m1.id, 42, m2.id]))
-
classmethod
search
(*args, **kwargs)¶ Shortcut for
sheraf.queryset.QuerySet.search()
.- Returns
-
-
class
sheraf.models.indexation.
IndexedModel
¶ Bases:
sheraf.models.indexation.BaseIndexedModel
Top-level indexed models.
Those models are stored at the root of the database. They must have a table parameter defined and an id attribute.
They can have a database_name attribute. If it is set, then in a default connection context:
create()
will store the new model instances in this database;read()
andall()
(etc.) will read in priority in this database, and then in the default database.delete()
will try to delete the model from this database, and by default in the default database.
However, if a database_name is explicitly passed to
sheraf.databases.connection()
, then every action will be performed on this database, ignoring the model database_name attribute.-
classmethod
create
(*args, **kwargs)¶ Create a model instance.
- Parameters
default – The data structure that will be used to store the model state.
**kwargs – Any model attribute can be initialized with the matching keyword.
- Returns
The newly created model.
>>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute(default="John Doe") ... >>> with sheraf.connection(commit=True): ... cowboy = Cowboy.create() ... assert "John Doe" == cowboy.name ... ... cowboy = Cowboy.create(name="George Abitbol") ... assert "George Abitbol" == cowboy.name ... ... Cowboy.create(this_attribute_does_not_exist="something") # raises a TypeError Traceback (most recent call last): ... TypeError: TypeError: create() got an unexpected keyword argument 'this_attribute_does_not_exist'
The function can also create sub-models recursively:
>>> class Horse(sheraf.InlineModel): ... name = sheraf.SimpleAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute(default="John Doe") ... horse = sheraf.InlineModelAttribute(Horse) ... >>> with sheraf.connection(): ... cowboy = Cowboy.create(name="George Abitbol", horse={"name": "Jolly Jumper"}) ... cowboy.horse.name 'Jolly Jumper'
-
class
sheraf.models.indexation.
IndexedModelMetaclass
¶ Bases:
sheraf.models.base.BaseModelMetaclass
Contains the mapping of tables (name of models) to their corresponding model definitions
-
class
sheraf.models.indexation.
SimpleIndexedModel
¶
Model flavors¶
-
class
sheraf.models.
AttributeModel
¶ Bases:
sheraf.models.attributes.NamedAttributesModel
,sheraf.models.indexation.SimpleIndexedModel
This model is expected to be used with
IndexedModelAttribute
.
-
sheraf.models.
AutoModel
¶ alias of
sheraf.models.UUIDAutoModel
-
class
sheraf.models.
BaseAutoModel
¶ Bases:
object
BaseAutoModel
are regular models which ‘table’ parameter automatically takes the lowercase class name. It should only be used with unit tests.>>> class MyWonderfulClass(sheraf.AutoModel): ... pass ... >>> assert MyWonderfulClass.table == "mywonderfulclass" >>> with sheraf.connection(): ... m = MyWonderfulClass.create() ... assert m.table == "mywonderfulclass"
-
class
sheraf.models.
BaseAutoModelMetaclass
¶
-
class
sheraf.models.
IntAutoModel
¶ Bases:
sheraf.models.BaseAutoModel
,sheraf.models.IntOrderedNamedAttributesModel
-
class
sheraf.models.
IntIndexedIntAttributesModel
¶ Bases:
sheraf.models.attributes.IntAttributesModel
,sheraf.models.IntIndexedModel
,sheraf.models.indexation.IndexedModel
The ids of this models are integers, and the ids of its attributes are also integers.
-
class
sheraf.models.
IntIndexedModel
¶ Bases:
object
Model using integers as ids.
By default ids are 64bits integers.
>>> class MyIntModel(sheraf.IntIndexedModel): ... table = "my_int_model" ... >>> with sheraf.connection(): ... MyIntModel.create().id 383428472384721983
-
class
sheraf.models.
IntIndexedNamedAttributesModel
¶ Bases:
sheraf.models.attributes.NamedAttributesModel
,sheraf.models.IntIndexedModel
,sheraf.models.indexation.IndexedModel
The ids of this model are integers, and attributes are named.
-
class
sheraf.models.
IntOrderedNamedAttributesModel
¶ Bases:
sheraf.models.attributes.NamedAttributesModel
,sheraf.models.IntIndexedModel
,sheraf.models.indexation.IndexedModel
The ids are 64bits integers, distributed ascendently starting at 0.
-
sheraf.models.
Model
¶
-
class
sheraf.models.
UUIDAutoModel
¶ Bases:
sheraf.models.BaseAutoModel
,sheraf.models.UUIDIndexedDatedNamedAttributesModel
-
class
sheraf.models.
UUIDIndexedDatedNamedAttributesModel
¶ Bases:
sheraf.models.attributes.DatedNamedAttributesModel
,sheraf.models.UUIDIndexedModel
,sheraf.models.indexation.IndexedModel
The ids of this model are UUID4, the attributes are named, and any modification on the model will update its modification datetime.
-
class
sheraf.models.
UUIDIndexedModel
¶ Bases:
object
Model using uuid4 as ids. Ids are stored as strings.
>>> class MyUUIDModel(sheraf.IntIndexedModel): ... table = "my_uuid_model" ... >>> with sheraf.connection(): ... MyIntModel.create().id "e4bb714e-b5a8-40d6-bb69-ab3b932fbfe0"
-
class
sheraf.models.
UUIDIndexedNamedAttributesModel
¶ Bases:
sheraf.models.attributes.NamedAttributesModel
,sheraf.models.UUIDIndexedModel
,sheraf.models.indexation.IndexedModel
The ids of this model are UUID4, and attributes are named.
-
class
sheraf.models.attributes.
DatedNamedAttributesModel
¶ Bases:
sheraf.models.attributes.NamedAttributesModel
Model with creation and modification datetimes.
Creation date is automatically saved. It will not change during object life. Date of modification is automatically saved when an attribute is modified and refers to the moment the transaction is committed. At creation time, date of modification and date of creation are equal.
-
creation_datetime
()¶ The date the object has been created. By now it refers to the date the method
create()
has been called, and not the date the transaction has been committed.- Returns
datetime.datetime
or None if the object has not been committed yet.
-
last_update_datetime
()¶ The date of the last transaction commit involving a modification in this object.
- Returns
datetime.datetime
or None if the object has not been committed yet.
-
save
()¶ Updates
last_update_datetime()
value and saves all the model attributes.
-
-
class
sheraf.models.attributes.
IntAttributesModel
¶ Bases:
sheraf.models.base.BaseModel
-
class
sheraf.models.attributes.
NamedAttributesModel
¶ Bases:
sheraf.models.base.BaseModel
-
class
sheraf.models.inline.
InlineModel
(**kwargs)¶ Bases:
sheraf.models.attributes.NamedAttributesModel
InlineModel
behaves like a regular model, but it is not indexed by itself. This has several consequences: - Thetable
attribute is not needed. - Theread()
method is not available.InlineModel
aims to be used in combination withInlineModelAttribute
.>>> class Gun(sheraf.InlineModel): ... nb_bullets = sheraf.IntegerAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute() ... gun = sheraf.InlineModelAttribute(Gun) ... >>> with sheraf.connection(commit=True): ... george = Cowboy.create( ... name="George Abitbol", ... gun=Gun.create(nb_bullets=5), ... ) ... assert 5 == george.gun.nb_bullets
You can manage your own indexation by combining
InlineModelAttribute
with a collection attribute, likeDictAttribute
.>>> class Gun(sheraf.InlineModel): ... nb_bullets = sheraf.IntegerAttribute() ... >>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute() ... guns = sheraf.LargeDictAttribute( ... sheraf.InlineModelAttribute(Gun) ... ) ... >>> with sheraf.connection(commit=True): ... george = Cowboy.create( ... name="George Abitbol", ... guns = { ... "martha": Gun.create(nb_bullets=6), ... "gretta": Gun.create(nb_bullets=5), ... } ... ) ... assert 6 == george.guns["martha"].nb_bullets
InlineModel
can also be anonymous. To create an anonymous model instance, just pass the attributes list as parameter of the class.>>> class Cowboy(sheraf.Model): ... table = "cowboy" ... name = sheraf.SimpleAttribute() ... horse = sheraf.InlineModelAttribute( ... sheraf.InlineModel( ... name=sheraf.SimpleAttribute() ... ) ... ) ... >>> with sheraf.connection(commit=True): ... george = Cowboy.create(horse=dict(name="Jolly Jumper")) ... george.horse.name 'Jolly Jumper'