Merge branch 'v0.4' of git://github.com/hmarr/mongoengine into v0.4

This commit is contained in:
Steve Challis
2010-09-29 23:39:09 +01:00
8 changed files with 144 additions and 26 deletions

View File

@@ -255,6 +255,7 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
'index_background': False,
'index_drop_dups': False,
'index_opts': {},
'queryset_class': QuerySet,
}
meta.update(base_meta)

View File

@@ -1,5 +1,5 @@
from pymongo import Connection
import multiprocessing
__all__ = ['ConnectionError', 'connect']
@@ -8,12 +8,12 @@ _connection_settings = {
'host': 'localhost',
'port': 27017,
}
_connection = None
_connection = {}
_db_name = None
_db_username = None
_db_password = None
_db = None
_db = {}
class ConnectionError(Exception):
@@ -22,32 +22,39 @@ class ConnectionError(Exception):
def _get_connection():
global _connection
identity = get_identity()
# Connect to the database if not already connected
if _connection is None:
if _connection.get(identity) is None:
try:
_connection = Connection(**_connection_settings)
_connection[identity] = Connection(**_connection_settings)
except:
raise ConnectionError('Cannot connect to the database')
return _connection
return _connection[identity]
def _get_db():
global _db, _connection
identity = get_identity()
# Connect if not already connected
if _connection is None:
_connection = _get_connection()
if _connection.get(identity) is None:
_connection[identity] = _get_connection()
if _db is None:
if _db.get(identity) is None:
# _db_name will be None if the user hasn't called connect()
if _db_name is None:
raise ConnectionError('Not connected to the database')
# Get DB from current connection and authenticate if necessary
_db = _connection[_db_name]
_db[identity] = _connection[identity][_db_name]
if _db_username and _db_password:
_db.authenticate(_db_username, _db_password)
_db[identity].authenticate(_db_username, _db_password)
return _db
return _db[identity]
def get_identity():
identity = multiprocessing.current_process()._identity
identity = 0 if not identity else identity[0]
return identity
def connect(db, username=None, password=None, **kwargs):
"""Connect to the database specified by the 'db' argument. Connection
settings may be provided here as well if the database is not running on

View File

@@ -56,7 +56,7 @@ class Document(BaseDocument):
__metaclass__ = TopLevelDocumentMetaclass
def save(self, safe=True, force_insert=False):
def save(self, safe=True, force_insert=False, validate=True):
"""Save the :class:`~mongoengine.Document` to the database. If the
document already exists, it will be updated, otherwise it will be
created.
@@ -67,8 +67,10 @@ class Document(BaseDocument):
:param safe: check if the operation succeeded before returning
:param force_insert: only try to create a new document, don't allow
updates of existing documents
:param validate: validates the document; set to ``False`` for skiping
"""
self.validate()
if validate:
self.validate()
doc = self.to_mongo()
try:
collection = self.__class__.objects._collection

View File

@@ -512,6 +512,10 @@ class BinaryField(BaseField):
raise ValidationError('Binary value is too long')
class GridFSError(Exception):
pass
class GridFSProxy(object):
"""Proxy object to handle writing and reading of files to and from GridFS
@@ -527,6 +531,7 @@ class GridFSProxy(object):
obj = self.get()
if name in dir(obj):
return getattr(obj, name)
raise AttributeError
def __get__(self, instance, value):
return self
@@ -545,12 +550,18 @@ class GridFSProxy(object):
self.grid_id = self.newfile._id
def put(self, file, **kwargs):
if self.grid_id:
raise GridFSError('This document alreay has a file. Either delete '
'it or call replace to overwrite it')
self.grid_id = self.fs.put(file, **kwargs)
def write(self, string):
if not self.newfile:
if self.grid_id:
if not self.newfile:
raise GridFSError('This document alreay has a file. Either '
'delete it or call replace to overwrite it')
else:
self.new_file()
self.grid_id = self.newfile._id
self.newfile.write(string)
def writelines(self, lines):

View File

@@ -344,6 +344,8 @@ class QuerySet(object):
mongo_query = {}
for key, value in query.items():
parts = key.split('__')
indices = [(i, p) for i, p in enumerate(parts) if p.isdigit()]
parts = [part for part in parts if not part.isdigit()]
# Check for an operator and transform to mongo-style if there is
op = None
if parts[-1] in operators + match_operators + geo_operators:
@@ -381,7 +383,9 @@ class QuerySet(object):
"been implemented" % op)
elif op not in match_operators:
value = {'$' + op: value}
for i, part in indices:
parts.insert(i, part)
key = '.'.join(parts)
if op is None or key not in mongo_query:
mongo_query[key] = value
@@ -762,7 +766,8 @@ class QuerySet(object):
return mongo_update
def update(self, safe_update=True, upsert=False, **update):
"""Perform an atomic update on the fields matched by the query.
"""Perform an atomic update on the fields matched by the query. When
``safe_update`` is used, the number of affected documents is returned.
:param safe: check if the operation succeeded before returning
:param update: Django-style update keyword arguments
@@ -774,8 +779,10 @@ class QuerySet(object):
update = QuerySet._transform_update(self._document, **update)
try:
self._collection.update(self._query, update, safe=safe_update,
upsert=upsert, multi=True)
ret = self._collection.update(self._query, update, multi=True,
upsert=upsert, safe=safe_update)
if ret is not None and 'n' in ret:
return ret['n']
except pymongo.errors.OperationFailure, err:
if unicode(err) == u'multi not coded yet':
message = u'update() method requires MongoDB 1.1.3+'
@@ -783,7 +790,8 @@ class QuerySet(object):
raise OperationError(u'Update failed (%s)' % unicode(err))
def update_one(self, safe_update=True, upsert=False, **update):
"""Perform an atomic update on first field matched by the query.
"""Perform an atomic update on first field matched by the query. When
``safe_update`` is used, the number of affected documents is returned.
:param safe: check if the operation succeeded before returning
:param update: Django-style update keyword arguments
@@ -795,11 +803,14 @@ class QuerySet(object):
# Explicitly provide 'multi=False' to newer versions of PyMongo
# as the default may change to 'True'
if pymongo.version >= '1.1.1':
self._collection.update(self._query, update, safe=safe_update,
upsert=upsert, multi=False)
ret = self._collection.update(self._query, update, multi=False,
upsert=upsert, safe=safe_update)
else:
# Older versions of PyMongo don't support 'multi'
self._collection.update(self._query, update, safe=safe_update)
ret = self._collection.update(self._query, update,
safe=safe_update)
if ret is not None and 'n' in ret:
return ret['n']
except pymongo.errors.OperationFailure, e:
raise OperationError(u'Update failed [%s]' % unicode(e))
@@ -988,7 +999,8 @@ class QuerySetManager(object):
self._collection = db[collection]
# owner is the document that contains the QuerySetManager
queryset = QuerySet(owner, self._collection)
queryset_class = owner._meta['queryset_class'] or QuerySet
queryset = queryset_class(owner, self._collection)
if self._manager_func:
if self._manager_func.func_code.co_argcount == 1:
queryset = self._manager_func(queryset)