Document API

Documents represent database records. Each document is a (in)complete subset of fields contained in a record. Available data types and query mechanisms are determined by the storage in use.

The API was inspired by Django, MongoKit, WTForms, Svarga and several other projects. It was important to KISS (keep it simple, stupid), DRY (do not repeat yourself) and to make the API as abstract as possible so that it did not depend on backends and yet did not get in the way.

class doqu.document_base.Document(**kw)

Base class for document schemata.

Wrapper for a record with predefined metadata.

Usage:

>>> from doqu import Document
>>> from doqu.validators import AnyOf

>>> class Note(Document):
...     structure = {
...         'text': unicode,
...         'is_note': bool,
...     }
...     defaults = {
...         'is_note': True,
...     }
...     validators = {
...         'is_note': [AnyOf([True])],
...     }
...
...     def __unicode__(self):
...         return u'{text}'.format(**self)

To save model instances and retrieve them you will want a storage:

>>> from doqu import get_db

>>> db = get_db(backend='doqu.ext.tokyo_tyrant', port=1983)

# and another one, just for testing (yep, the real storage is the same)
>>> other_db = get_db(backend='doqu.ext.tokyo_tyrant', port=1983)

# let's make sure the storage is empty
>>> db.clear()

See documentation on methods for more details.

convert_to(other_schema, overrides=None)

Returns the document as an instance of another model. Copies attributes of current instance that can be applied to another model (i.e. only overlapping attributes – ones that matter for both models). All other attributes are re-fetched from the database (if we know the key).

Note

The document key is preserved. This means that the new instance represents the same document, not a new one. Remember that models are “views”, and to “convert” a document does not mean copying; it can however imply adding attributes to the existing document.

Neither current instance nor the returned one are saved automatically. You will have to do it yourself.

Please note that trying to work with the same document via different instances of models whose properties overlap can lead to unpredictable results: some properties can be overwritten, go out of sync, etc.

Parameters:
  • other_model – the model to which the instance should be converted.
  • overrides – a dictionary with attributes and their values that should be set on the newly created model instance. This dictionary will override any attributes that the models have in common.

Usage:

>>> class Contact(Note):
...     structure = {'name': unicode}
...     validators = {'name': [required()]}  # merged with Note's
...
...     def __unicode__(self):
...         return u'{name} ({text})'.format(**self)

>>> note = Note(text='phone: 123-45-67')
>>> note
<Note phone: 123-45-67>

# same document, contact-specific data added
>>> contact = note.convert_to(Contact, {'name': 'John Doe'})
>>> contact
<Contact John Doe (phone: 123-45-67)>
>>> contact.name
'John Doe'
>>> contact.text
'phone: 123-45-67'

# same document, contact-specific data ignored
>>> note2 = contact.convert_to(Note)
>>> note2
<Note phone: 123-45-67>
>>> note2.name
Traceback (most recent call last):
...
AttributeError: 'Note' object has no attribute 'name'
>>> note2.text
'phone: 123-45-67'
delete()

Deletes the object from the associated storage.

classmethod object(storage, pk)

Returns an instance of given document class associated with a record stored with given primary key in given storage. Usage:

event = Event.object(db, key)
Parameters:
classmethod objects(storage)

Returns a query for records stored in given storage and associates with given document class. Usage:

events = Event.objects(db)
Parameters:
pk

Returns current primary key (if any) or None.

save(storage=None, keep_key=False)

Saves instance to given storage.

Parameters:
  • storage – the storage to which the document should be saved. If not specified, default storage is used (the one from which the document was retrieved of to which it this instance was saved before).
  • keep_key – if True, the primary key is preserved even when saving to another storage. This is potentially dangerous because existing unrelated records can be overwritten. You will only need this when copying a set of records that reference each other by primary key. Default is False.
save_as(key=None, storage=None, **kwargs)

Saves the document under another key (specified as key or generated) and returns the newly created instance.

Parameters:
  • key – the key by which the document will be identified in the storage. Use with care: any existing record with that key will be overwritten. Pay additional attention if you are saving the document into another storage. Each storage has its own namespace for keys (unless the storage objects just provide different ways to access a single real storage). If the key is not specified, it is generated automatically by the storage.

See save() for details on other params.

Usage:

>>> db.clear()
>>> note = Note(text="hello")   # just create the item

# WRONG:

>>> note.save()               # no storage; don't know where to save
Traceback (most recent call last):
...
AttributeError: cannot save model instance: storage is not defined neither in instance nor as argument for the save() method
>>> note.save_as()            # same as above
Traceback (most recent call last):
...
AttributeError: cannot save model instance: storage is not defined neither in instance nor as argument for the save() method

# CORRECT:

>>> new_key = note.save(db)                   # storage provided, key generated
>>> new_key
u'1'
>>> new_obj = note.save_as(storage=db)        # same as above
>>> new_obj
<Note hello>
>>> new_obj.pk  # new key
u'2'
>>> new_obj.text  # same data
'hello'
>>> new_key = note.save()                     # same storage, same key
>>> new_key
u'1'
>>> new_obj = note.save_as()                  # same storage, autogenerated new key
>>> new_obj.pk
u'3'
>>> new_obj = note.save_as('custom_key')      # same storage, key "123"
>>> new_obj.pk
'custom_key'

>>> note.save_as(123, other_db)     # other storage, key "123"
<Note hello>
>>> note.save_as(storage=other_db)  # other storage, autogenerated new key
<Note hello>

Warning

Current implementation may lead to data corruption if the document comes from one database and is being saved to another one, managed by a different backend. Use with care.

validate()

Checks if instance data is valid. This involves a) checking whether all values correspond to the declated structure, and b) running all Validators against the data dictionary.

Raises ValidationError if something is wrong.

Note

if the data dictionary does not contain some items determined by structure or validators, these items are not checked.

Note

The document is checked as is. There are no side effects. That is, if some required values are empty, they will be considered invalid even if default values are defined for them. The save() method, however, fills in the default values before validating.

doqu.document_base.Many

alias of OneToManyRelation

Previous topic

API reference

Next topic

Document Fields

This Page