
Security News
Node.js TSC Votes to Stop Distributing Corepack
Corepack will be phased out from future Node.js releases following a TSC vote.
.. image:: https://travis-ci.org/zzzsochi/yadm.svg?branch=master :target: https://travis-ci.org/zzzsochi/yadm
.. image:: https://coveralls.io/repos/github/zzzsochi/yadm/badge.svg?branch=master :target: https://coveralls.io/github/zzzsochi/yadm?branch=master
It's small and simple ODM for use with MongoDB.
.. Full documentation: http://yadm.readthedocs.org
YADM support MongoDB version 3.x only. MongoDB 2.x is not supported.
Minimal version of python — 3.6.
.. code:: python
from datetime import datetime
import pymongo
from yadm import Database
from yadm import Document, EmbeddedDocument
from yadm import fields
from yadm.serialize import to_mongo
class User(Document):
__collection__ = 'users'
name = fields.StringField()
email = fields.EmailField()
class PostLogItem(EmbeddedDocument):
op = fields.StringField(choices=['created', 'comment_added'])
at = fields.DatetimeField()
data = fields.MongoMapField()
class Post(Document):
__collection__ = 'posts'
user = fields.ReferenceField(User)
created_at = fields.DatetimeField(auto_now=True)
title = fields.StringField()
body = fields.StringField()
log = fields.ListField(fields.EmbeddedDocumentField(PostLogItem))
class Comment(Document):
__collection__ = 'comments'
user = fields.ReferenceField(User)
created_at = fields.DatetimeField(auto_now=True)
post = fields.ReferenceField(Post)
text = fields.StringField()
All documents creates from class Document
. You can use multiple inheritance.
__collection__
magic attribute setups the collection name for documents of model.
.. code:: python
client = pymongo.MongoClient('mongodb://localhost:27017')
db = Database(client, 'blog')
Database
object is a wrapper about pymongo
or motor
Database
.
.. code:: python
user = User(name='Bill', email='bill@galactic.hero')
db.insert_one(user)
Just insert document to database.
.. code:: python
post = Post()
post.user = user
post.title = 'Small post'
post.body = 'Bla-bla-bla...'
post.log = [PostLogItem(op='created', at=datetime.utcnow())]
db.insert_one(post)
You can fill documents as above.
.. code:: python
comment = Comment()
comment.user = user
comment.post = post
comment.text = "RE: Bla-bla-bla..."
db.insert_one(comment)
db.update_one(post, push={
'log': to_mongo(PostLogItem(op='comment_added',
at=comment.created_at,
data={
'comment': comment.id,
'user': comment.user.id,
}))
})
We add log item to post's log. This is very usefull case.
.. code:: python
qs = db(Post).find({'title': {'$regex': '^S'}})
assert qs.count() > 0
db(Post)
creates the QuerySet
object;find
method get the raw-query and return new QuerySet
object with updated criteria;count
method make the query to database and return value... code:: python
for post in qs:
assert post.title.startswith('S')
__iter__
method make the find
-query and returns the generator of documents.
Get the first finded document.
.. code:: python
post = db(Post).find_one({'user': user.id})
Get the document by id from primary.
.. code:: python
user = db.get_document(User, user.id)
.. code:: python
user = post.user
Get attribute with reference makes the query to referred collection. Warning: N+1 problem!
We have a cache in QuerySet
object and get one referred document only once for one queryset.
.. code:: python
comments = db(Comment).find({'post': post.id}).sort(('created_at', 1))
for comment in comments.lookup('user'):
print(comment.user.name, comment.text)
This code create the aggregate query with $lookup
statement for resolve the references.
.. code:: python
agg = (db.aggregate(Comment)
.match(user=user.id)
.group(_id='post', count={'$sum': 1})
.sort(count=-1))
for item in agg:
print(item)
Or traditional MongoDB syntax:
.. code:: python
agg = db.aggregate(Comment, pipeline=[
{'match': {'user': user.id}},
{'group': {'_id': 'post', 'count': {'$sum': 1}}},
{'sort': {'count': -1}},
])
comment
methods for QuerySet
and Aggregation
to specify comment feature of MongoDB.Aggregation.hint
method.Database.estimated_document_count
method for quickly count documents in the collection.QuerySet.hint
for specify index for query.A Big Rewrite <https://www.youtube.com/watch?v=xCGu5Z_vaps>
_ document logic:
Document.__raw__
now contains only data from pymongo, without any AttributeNotSet
or NotLoaded
;Document.__changed__
is removed: all changes reflects to Document.__cache__
;Document.__not_loaded__
frozenset of fields whitch not loaded by projection;Document.__new_document__
flag is True
for document's objects whitch created directly in your code;Document.__log__
list-like container with log of document changes (unstable API at now);Document.__data__
is removed as deprecated;Update for minimal versions of pymongo (3.7) and motor (2.0):
Database.bulk_write
;Database.insert_one
, Database.insert_many
and Database.delete_one
;Database.insert
, Database.remove
;Database.bulk
(without deprecation period, sorry);QuerySet.count_documents
;QuerySet.update_one
and QuerySet.update_many
;QuerySet.delete_one
and QuerySet.delete_many
;QuerySet.find_one_and_update
, QuerySet.find_one_and_replace
and QuerySet.find_one_and_delete
;QuerySet.count
;QuerySet.update
, QuerySet.remove
and QuerySet.find_and_modify
;QuerySet.with_id
;Simple interface for build lookups: QuerySet.lookup
;
Remove bcc
argument from MoneyField
;
Add Decimal128Field
.
asyncio
support;ReferencesListField
for lists of references.projection
argument to Database.get_document
and Database.reload
;Document.__default_projection__
attribute.EnumField
for save enum.Enum
;EnumStateField
for simple state machines based on enum.Enum
.QuerySet.batch_size
method for setup batch size for cursor;ReferenceField.from_mongo
try to get document from primary
if not found by default.QuerySet.read_primary
method for simple setup read_preference.Primary
.TimedeltaField
for stores durations;SimpleEmbeddedDocumentField
for simply create embedded documents... code:: python
class Doc(Document):
embedded = SimpleEmbeddedDocumentField({
'i': IntegerField(),
's': StringField(),
})
StaticField
for static data.write_concern
) for write operations;create_fake
save the documents with write concern "majority" by default.Database.get_document
;TypedEmbeddedDocumentField
;reload
argument of Database.update_one
must be keyword
(may be backward incompotable).Money
;Money
:
Money
type. Now it is not subclass of Decimal
;yadm.fields.money.currency.DEFAULT_CURRENCY_STORAGE
;QuerySet.find_in
for $in
queries with specified order;Bulk
:
Bulk.update_one(document, **kw)
: method for add update one document in bulk;Bulk.find(query).update(**kw)
: update many documents by query;Bulk.find(query).upsert().update(**kw)
: upsert document;Bulk.find(query).remove(**kw)
: remove documents;Add QuerySet.ids
method for get only documents id's from queryset;
Add Money.total_cents
method and Money.from_cents
classmethod;
Add cacheing on queryset level and use it for ReferenceField
;
Add mongo aggregation framework support;
Add read_preference
setting;
Add exc
argument to QuerySet.find_one
for raise exception if not found;
Add multi
argument to QuerySet.remove
;
Deprecate QuerySet.with_id
;
Refactoring.
Change document structure. No more bad BaseDocument.__data__
attribute:
BaseDocument.__raw__
: raw data from mongo;BaseDocument.__cache__
: cached objects, casted with fields;BaseDocument.__changed__
: changed objects.Changes api for custom fields:
prepare_value
called only for setattr;to_mongo
called only for save objects to mongo;from_mongo
called only for load values from BaseDocument.__raw__
;Field.default
attribute. Use Field.get_default
method;Field.get_if_not_loaded
and Field.get_if_attribute_not_set
method;NotLoadedError
if field not loaded from projection;Changes in ReferenceField
:
BrokenReference
if link is bloken;NotBindingToDatabase
if document not saved to database;smart_null
keyword for Field
;
Fields in document must be instances (not classes!);
Remove ArrayContainer
and ArrayContainerField
;
Remove old MapIntKeysField
and MapObjectIdKeysField
. Use new MapCustomKeysField
;
Add Database.update_one
method for run simple update query with specified document;
Add QuerySet.distinct
;
serialize.from_mongo
now accept not_loaded
sequence with filed names who must mark as not loaded, parent
and name
;
serialize.to_mongo
do not call FieldDescriptor.__set__
;
Fakers! Subsystem for generate test objects;
Tests now use pytest;
And more, and more...
FAQs
Yet Another Document Mapper (ODM) for MongoDB
We found that yadm demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Corepack will be phased out from future Node.js releases following a TSC vote.
Research
Security News
Research uncovers Black Basta's plans to exploit package registries for ransomware delivery alongside evidence of similar attacks already targeting open source ecosystems.
Security News
Oxlint's beta release introduces 500+ built-in linting rules while delivering twice the speed of previous versions, with future support planned for custom plugins and improved IDE integration.