Dico

A database-agnostic modeling system
Download

Dico Ranking & Summary

Advertisement

  • Rating:
  • License:
  • BSD License
  • Price:
  • FREE
  • Publisher Name:
  • Fabrice Aneche
  • Publisher web site:
  • https://github.com/akhenakh/

Dico Tags


Dico Description

Dico is a database-agnostic modeling system, heavily inspired by DictShield.Developer commentsAfter using DictShield, a "database-agnostic modeling system", I've found the idea very usefull when dealing with NoSQL database, but want to choose another direction.Most of the time you're manipulating data from a database server, modify it and save, especially in web development.Here are the usual patterns with Dico:Create an object from scratch and validate fieldsclass BlogPost(Document): id = IntegerField() title = StringField(required=True, max_length=40) body = StringField(max_length=4096) creation_date = DateField(required=True, default=datetime.datetime.utcnow)>>> post = BlogPost() >>> post.body = 'I'm a new post'>>> post.validate()False>>> post.title = 'New post'>>> post.validate()True>>> post2 = BlogPost(title='Hop hop', body='thebody')Store it/Serialize it>>> post.dict_for_save(){'id': 45, 'title': 'New post', 'body': "I'm a new post"}If dict_for_save is called on not valid data it will raise a ValidationException.Validate an object populate from existing data and modify it>>> dict_from_db = {'id': '50000685467ffd11d1000001', 'title': 'A post', 'body': "I'm a post"}>>> post = BlogPost(**dict_from_db)>>> post.title"I'm a title from the DB">>> post.title = 'New title from cli'>>> post.validate()TrueSee modified fields since creation>>> post.modified_fields()# Usefull for Mongo update>>> post.dict_for_changes(){'title': 'New title from cli'}Note that dict_for_changes does not contains fields modifier by default=.Create an object with partial dataWhen working with real data, you will not fetch every fields from your DB, but still wants validation.>>> dict_from_db = {'body': "I'm a post"}>>> post = BlogPost(**dict_from_db)>>> post.validate()False>>> post.validate_partial()True>>> post2.BlogPost()>>> post2.title = 3>>> post2.validate_partial()False>>> post2.title = 'New title'>>> post2.validate_partial()TrueListFieldA list can contains n elements of a field's type.class User(dico.Document): friends = dico.ListField(dico.IntegerField(), min_length=2, max_length=4)Field types- BooleanField- StringField- IPAddressField- URLField- EmailField- IntegerField- FloatField- DateTimeField- ListField- EmbeddedDocumentFieldPrepare object for export and adjust visibility of fieldsclass User(Document): id = IntegerField(required=True) firstname = StringField(required=True, max_length=40) email = EmailField() owner_fields = public_fields = >>> user = User(**dict_from_db)>>> user.dict_for_owner(){'firstname': 'Paul', 'email':'paul_sponge@yahoo.com'}>>> user.dict_for_public(){'firstname': 'Paul'}>> user.dict_for_save(){'firstname': 'Paul', 'email':'paul_sponge@yahoo.com', 'id': 56}Aliases for field inputIn mongo the id is called _id so we need a way to make the Document accept it is as id.class User(Document): id = ObjectIdField(required=True, aliases=)>>> user = User(_id=ObjectId('50000685467ffd11d1000001'))>>> user.id'50000685467ffd11d1000001'Hooks filtersThere are 3 hooks filter to manipulate data before and after exports, it should be a list of callable to filter- pre_save_filter- pre_owner_filter- pre_public_filterHere we are renaming firstname field to first_nameclass User(Document): firstname = StringField(required=True, max_length=40) def save_filter(dict): dict = dict del dict return dict public_fields = pre_save_filter = >>> user = User(firstname='Bob')>>> user.dict_for_save(){'first_name':'Bob'}>>> user.dict_for_public(){'firstname':'Bob'}You can use partial to call function with argumentsfrom functools import partialclass User(dico.Document): id = dico.IntegerField() def rename_field(old_field, new_field, filter_dict): if old_field in filter_dict: filter_dict = filter_dict del filter_dict return filter_dict pre_save_filter = public_fields = @properties visibilityProperties are suitable for serializationclass User(Document): firstname = StringField(required=True, max_length=40) name = StringField(required=True, max_length=40) @properties def full_name(self): return firstname + ' ' + name public_fields = >>> user.dict_for_public() {'full_name': 'Sponge Bob'}Embedded fieldsYou may embed document in document, directly or within a listclass OAuthToken(dico.Document): consumer_secret = dico.StringField(required=True, max_length=32) active = dico.BooleanField(default=True) token_id = dico.mongo.ObjectIdField(required=True, default=ObjectId)class User(dico.Document): id = dico.IntegerField() token = dico.EmbeddedDocumentField(OAuthToken)>>> user = User()>>> user.token = 3>>> user.validate()False>>> user.token = OAuthToken()>>> user.validate()False>>> user.token = OAuthToken(consumer_secret='fac470fcd')>>> user.validate()Falseclass OAuthToken(dico.Document): consumer_secret = dico.StringField(required=True, max_length=32) active = dico.BooleanField(default=True) token_id = dico.mongo.ObjectIdField(required=True, default=ObjectId)class User(dico.Document): id = dico.IntegerField() tokens = dico.ListField(dico.EmbeddedDocumentField(OAuthToken))>>> user = User()>>> user.id = 2>>> token = OAuthToken()>>> token.consumer_secret = 'fac470fcd'>>> token2 = OAuthToken()>>> token2.consumer_secret = 'fac470fcd'>>> user.tokens = Example usage with mongoWe know we want to update only some fields firstname and email, so we fetch the object with no field, update our fields then update, later we create a new user and save it. Not the rename_field function which is provided in Dico as shortcut.class User(Document): id = ObjectIdField(default=ObjectId(), required=True, aliases=) firstname = StringField(required=True, max_length=40) email = EmailField() pre_save_filter = owner_fields = public_fields = >>> user_dict = db.user.find_one({'email':'bob@sponge.com'}, [])>>> user = User(**user_dict)>>> user.firstname = 'Bob'>>> user.email = 'bob@yahoo.com'>>> user.validate_partial()True>>> db.user.update({'_id': user.id}, user.dict_for_modified_fields())>>> user = User()>>> user.email = 'sponge@bob.com'>>> user.validate()True>>> db.user.save(user.dict_for_save())# note this trick here we are reusing the public fields list from the user object to query only# this specific fields and make queries faster>>> user_dict = db.user.find_one({'email':'bob@yahoo.com', User.public_fields)>>> user = User(**user_dict)>>> user.dict_for_public(){'id':'50000685467ffd11d1000001', 'firstname':'Bob'}Ideas- Convert all fields to json acceptable type, (for use with ujson directly), a param in dict_for_public(json_convert=True) ?- Use it as form validation? (I'm not sure I need this: my REST views are not exactly mapped to my objects)- Can external user modify this field? Eg id- Returns a representation of this Dico class as a JSON schema. (nizox)- Post save commit() reset modified fieldsDifferences with dictshield- dictshield raise ValueError while setting a property on a document if the data does not match the field, makes validate() useless- dictshield allows unknown properties to be set- dictshield does not use slots- dictshield is more complete but complexe- dictshield has separates files in packages, makes import boringInstallingDico is available via pypi.pip install dicoProduct's homepage


Dico Related Software