Compare commits

...

11 Commits

Author SHA1 Message Date
Ross Lawley
ab4d4e6230 Fix ReferenceField dbref = False 2012-09-18 21:37:45 +00:00
Ross Lawley
7cd38c56c6 Merge branch 'master' of github.com:MongoEngine/mongoengine into 0.7 2012-09-14 10:19:04 +00:00
Ross Lawley
864053615b Updated docs 2012-09-14 10:18:44 +00:00
Ross Lawley
db2366f112 Merge pull request #126 from mahmoudhossam/patch-1
Update docs/index.rst
2012-09-13 06:18:06 -07:00
Ross Lawley
4defc82192 Version Bump 2012-09-11 15:16:39 +00:00
Ross Lawley
5949970a95 Fixed index inheritance issues
firmed up testcases (MongoEngine/mongoengine#123) (MongoEngine/mongoengine#125)
2012-09-11 15:14:37 +00:00
Mahmoud Hossam
0ea4abda81 Update docs/index.rst
Correct link for the source.
2012-09-11 12:38:40 +03:00
Ross Lawley
5c6035d636 Updated upgrade docs for BinaryFields 2012-09-11 08:56:32 +00:00
Ross Lawley
a2183e3dcc Reverted EmbeddedDocuments meta handling.
You now can turn off inheritance (MongoEngine/mongoengine#119)
2012-09-07 13:23:46 +01:00
Ross Lawley
99637151b5 Updated version 2012-09-05 10:24:25 +01:00
Ross Lawley
a8e787c120 Update index spec generation so its not destructive (MongoEngine/mongoengine#113) 2012-09-04 14:39:19 +01:00
14 changed files with 164 additions and 30 deletions

View File

@@ -2,6 +2,23 @@
Changelog Changelog
========= =========
Changes in 0.7.5
================
- ReferenceFields with dbref=False use ObjectId instead of strings (MongoEngine/mongoengine#134)
See ticket for upgrade notes (https://github.com/MongoEngine/mongoengine/issues/134)
Changes in 0.7.4
================
- Fixed index inheritance issues - firmed up testcases (MongoEngine/mongoengine#123) (MongoEngine/mongoengine#125)
Changes in 0.7.3
================
- Reverted EmbeddedDocuments meta handling - now can turn off inheritance (MongoEngine/mongoengine#119)
Changes in 0.7.2
================
- Update index spec generation so its not destructive (MongoEngine/mongoengine#113)
Changes in 0.7.1 Changes in 0.7.1
================= =================
- Fixed index spec inheritance (MongoEngine/mongoengine#111) - Fixed index spec inheritance (MongoEngine/mongoengine#111)

View File

@@ -344,6 +344,10 @@ Its value can take any of the following constants:
their :file:`models.py` in the :const:`INSTALLED_APPS` tuple. their :file:`models.py` in the :const:`INSTALLED_APPS` tuple.
.. warning::
Signals are not triggered when doing cascading updates / deletes - if this
is required you must manually handle the update / delete.
Generic reference fields Generic reference fields
'''''''''''''''''''''''' ''''''''''''''''''''''''
A second kind of reference field also exists, A second kind of reference field also exists,

View File

@@ -50,4 +50,11 @@ Example usage::
signals.post_save.connect(Author.post_save, sender=Author) signals.post_save.connect(Author.post_save, sender=Author)
ReferenceFields and signals
---------------------------
Currently `reverse_delete_rules` do not trigger signals on the other part of
the relationship. If this is required you must manually handled the
reverse deletion.
.. _blinker: http://pypi.python.org/pypi/blinker .. _blinker: http://pypi.python.org/pypi/blinker

View File

@@ -34,10 +34,10 @@ To get help with using MongoEngine, use the `MongoEngine Users mailing list
Contributing Contributing
------------ ------------
The source is available on `GitHub <http://github.com/hmarr/mongoengine>`_ and The source is available on `GitHub <http://github.com/MongoEngine/mongoengine>`_ and
contributions are always encouraged. Contributions can be as simple as contributions are always encouraged. Contributions can be as simple as
minor tweaks to this documentation. To contribute, fork the project on minor tweaks to this documentation. To contribute, fork the project on
`GitHub <http://github.com/hmarr/mongoengine>`_ and send a `GitHub <http://github.com/MongoEngine/mongoengine>`_ and send a
pull request. pull request.
Also, you can join the developers' `mailing list Also, you can join the developers' `mailing list

View File

@@ -61,6 +61,13 @@ stored in rather than as string representations. Your code may need to be
updated to handle native types rather than strings keys for the results of updated to handle native types rather than strings keys for the results of
item frequency queries. item frequency queries.
BinaryFields
------------
Binary fields have been updated so that they are native binary types. If you
previously were doing `str` comparisons with binary field values you will have
to update and wrap the value in a `str`.
0.5 to 0.6 0.5 to 0.6
========== ==========

View File

@@ -12,7 +12,7 @@ from signals import *
__all__ = (document.__all__ + fields.__all__ + connection.__all__ + __all__ = (document.__all__ + fields.__all__ + connection.__all__ +
queryset.__all__ + signals.__all__) queryset.__all__ + signals.__all__)
VERSION = (0, 7, 1) VERSION = (0, 7, 5)
def get_version(): def get_version():

View File

@@ -508,6 +508,10 @@ class DocumentMetaclass(type):
attrs['_is_document'] = attrs.get('_is_document', False) attrs['_is_document'] = attrs.get('_is_document', False)
# EmbeddedDocuments could have meta data for inheritance
if 'meta' in attrs:
attrs['_meta'] = attrs.pop('meta')
# Handle document Fields # Handle document Fields
# Merge all fields from subclasses # Merge all fields from subclasses
@@ -571,6 +575,24 @@ class DocumentMetaclass(type):
superclasses[base._class_name] = base superclasses[base._class_name] = base
superclasses.update(base._superclasses) superclasses.update(base._superclasses)
if hasattr(base, '_meta'):
# Warn if allow_inheritance isn't set and prevent
# inheritance of classes where inheritance is set to False
allow_inheritance = base._meta.get('allow_inheritance',
ALLOW_INHERITANCE)
if (not getattr(base, '_is_base_cls', True)
and allow_inheritance is None):
warnings.warn(
"%s uses inheritance, the default for "
"allow_inheritance is changing to off by default. "
"Please add it to the document meta." % name,
FutureWarning
)
elif (allow_inheritance == False and
not base._meta.get('abstract')):
raise ValueError('Document %s may not be subclassed' %
base.__name__)
attrs['_class_name'] = '.'.join(reversed(class_name)) attrs['_class_name'] = '.'.join(reversed(class_name))
attrs['_superclasses'] = superclasses attrs['_superclasses'] = superclasses
@@ -745,21 +767,6 @@ class TopLevelDocumentMetaclass(DocumentMetaclass):
if hasattr(base, 'meta'): if hasattr(base, 'meta'):
meta.merge(base.meta) meta.merge(base.meta)
elif hasattr(base, '_meta'): elif hasattr(base, '_meta'):
# Warn if allow_inheritance isn't set and prevent
# inheritance of classes where inheritance is set to False
allow_inheritance = base._meta.get('allow_inheritance',
ALLOW_INHERITANCE)
if not base._is_base_cls and allow_inheritance is None:
warnings.warn(
"%s uses inheritance, the default for "
"allow_inheritance is changing to off by default. "
"Please add it to the document meta." % name,
FutureWarning
)
elif (allow_inheritance == False and
not base._meta.get('abstract')):
raise ValueError('Document %s may not be subclassed' %
base.__name__)
meta.merge(base._meta) meta.merge(base._meta)
# Set collection in the meta if its callable # Set collection in the meta if its callable

View File

@@ -25,6 +25,14 @@ class EmbeddedDocument(BaseDocument):
collection. :class:`~mongoengine.EmbeddedDocument`\ s should be used as collection. :class:`~mongoengine.EmbeddedDocument`\ s should be used as
fields on :class:`~mongoengine.Document`\ s through the fields on :class:`~mongoengine.Document`\ s through the
:class:`~mongoengine.EmbeddedDocumentField` field type. :class:`~mongoengine.EmbeddedDocumentField` field type.
A :class:`~mongoengine.EmbeddedDocument` subclass may be itself subclassed,
to create a specialised version of the embedded document that will be
stored in the same collection. To facilitate this behaviour, `_cls` and
`_types` fields are added to documents (hidden though the MongoEngine
interface though). To disable this behaviour and remove the dependence on
the presence of `_cls` and `_types`, set :attr:`allow_inheritance` to
``False`` in the :attr:`meta` dictionary.
""" """
# The __metaclass__ attribute is removed by 2to3 when running with Python3 # The __metaclass__ attribute is removed by 2to3 when running with Python3

View File

@@ -709,6 +709,10 @@ class ReferenceField(BaseField):
Bar.register_delete_rule(Foo, 'bar', NULLIFY) Bar.register_delete_rule(Foo, 'bar', NULLIFY)
.. note ::
`reverse_delete_rules` do not trigger pre / post delete signals to be
triggered.
.. versionchanged:: 0.5 added `reverse_delete_rule` .. versionchanged:: 0.5 added `reverse_delete_rule`
""" """
@@ -788,7 +792,7 @@ class ReferenceField(BaseField):
collection = self.document_type._get_collection_name() collection = self.document_type._get_collection_name()
return DBRef(collection, id_) return DBRef(collection, id_)
return "%s" % id_ return id_
def to_python(self, value): def to_python(self, value):
"""Convert a MongoDB-compatible type to a Python type. """Convert a MongoDB-compatible type to a Python type.

View File

@@ -398,6 +398,7 @@ class QuerySet(object):
or a **-** to determine the index ordering or a **-** to determine the index ordering
""" """
index_spec = QuerySet._build_index_spec(self._document, key_or_list) index_spec = QuerySet._build_index_spec(self._document, key_or_list)
index_spec = index_spec.copy()
fields = index_spec.pop('fields') fields = index_spec.pop('fields')
index_spec['drop_dups'] = drop_dups index_spec['drop_dups'] = drop_dups
index_spec['background'] = background index_spec['background'] = background
@@ -472,7 +473,9 @@ class QuerySet(object):
# Ensure document-defined indexes are created # Ensure document-defined indexes are created
if self._document._meta['index_specs']: if self._document._meta['index_specs']:
for spec in self._document._meta['index_specs']: index_spec = self._document._meta['index_specs']
for spec in index_spec:
spec = spec.copy()
fields = spec.pop('fields') fields = spec.pop('fields')
types_indexed = types_indexed or includes_types(fields) types_indexed = types_indexed or includes_types(fields)
opts = index_opts.copy() opts = index_opts.copy()
@@ -498,8 +501,10 @@ class QuerySet(object):
""" """
if isinstance(spec, basestring): if isinstance(spec, basestring):
spec = {'fields': [spec]} spec = {'fields': [spec]}
if isinstance(spec, (list, tuple)): elif isinstance(spec, (list, tuple)):
spec = {'fields': spec} spec = {'fields': list(spec)}
elif isinstance(spec, dict):
spec = dict(spec)
index_list = [] index_list = []
direction = None direction = None

View File

@@ -5,7 +5,7 @@
%define srcname mongoengine %define srcname mongoengine
Name: python-%{srcname} Name: python-%{srcname}
Version: 0.7.1 Version: 0.7.5
Release: 1%{?dist} Release: 1%{?dist}
Summary: A Python Document-Object Mapper for working with MongoDB Summary: A Python Document-Object Mapper for working with MongoDB

View File

@@ -1,7 +1,7 @@
from __future__ import with_statement from __future__ import with_statement
import unittest import unittest
from bson import DBRef from bson import DBRef, ObjectId
from mongoengine import * from mongoengine import *
from mongoengine.connection import get_db from mongoengine.connection import get_db
@@ -187,8 +187,8 @@ class FieldTest(unittest.TestCase):
self.assertEqual(group.members, [user]) self.assertEqual(group.members, [user])
raw_data = Group._get_collection().find_one() raw_data = Group._get_collection().find_one()
self.assertTrue(isinstance(raw_data['author'], basestring)) self.assertTrue(isinstance(raw_data['author'], ObjectId))
self.assertTrue(isinstance(raw_data['members'][0], basestring)) self.assertTrue(isinstance(raw_data['members'][0], ObjectId))
def test_recursive_reference(self): def test_recursive_reference(self):
"""Ensure that ReferenceFields can reference their own documents. """Ensure that ReferenceFields can reference their own documents.

View File

@@ -338,7 +338,6 @@ class DocumentTest(unittest.TestCase):
meta = {'allow_inheritance': False} meta = {'allow_inheritance': False}
self.assertRaises(ValueError, create_employee_class) self.assertRaises(ValueError, create_employee_class)
def test_allow_inheritance_abstract_document(self): def test_allow_inheritance_abstract_document(self):
"""Ensure that abstract documents can set inheritance rules and that """Ensure that abstract documents can set inheritance rules and that
_cls and _types will not be used. _cls and _types will not be used.
@@ -366,6 +365,31 @@ class DocumentTest(unittest.TestCase):
Animal.drop_collection() Animal.drop_collection()
def test_allow_inheritance_embedded_document(self):
# Test the same for embedded documents
class Comment(EmbeddedDocument):
content = StringField()
meta = {'allow_inheritance': False}
def create_special_comment():
class SpecialComment(Comment):
pass
self.assertRaises(ValueError, create_special_comment)
comment = Comment(content='test')
self.assertFalse('_cls' in comment.to_mongo())
self.assertFalse('_types' in comment.to_mongo())
class Comment(EmbeddedDocument):
content = StringField()
meta = {'allow_inheritance': True}
comment = Comment(content='test')
self.assertTrue('_cls' in comment.to_mongo())
self.assertTrue('_types' in comment.to_mongo())
def test_document_inheritance(self): def test_document_inheritance(self):
"""Ensure mutliple inheritance of abstract docs works """Ensure mutliple inheritance of abstract docs works
""" """
@@ -396,6 +420,9 @@ class DocumentTest(unittest.TestCase):
'indexes': ['name'] 'indexes': ['name']
} }
self.assertEqual(Animal._meta['index_specs'],
[{'fields': [('_types', 1), ('name', 1)]}])
Animal.drop_collection() Animal.drop_collection()
dog = Animal(name='dog') dog = Animal(name='dog')
@@ -417,6 +444,9 @@ class DocumentTest(unittest.TestCase):
'allow_inheritance': False, 'allow_inheritance': False,
'indexes': ['name'] 'indexes': ['name']
} }
self.assertEqual(Animal._meta['index_specs'],
[{'fields': [('name', 1)]}])
collection.update({}, {"$unset": {"_types": 1, "_cls": 1}}, multi=True) collection.update({}, {"$unset": {"_types": 1, "_cls": 1}}, multi=True)
# Confirm extra data is removed # Confirm extra data is removed
@@ -634,6 +664,12 @@ class DocumentTest(unittest.TestCase):
'allow_inheritance': True 'allow_inheritance': True
} }
self.assertEqual(BlogPost._meta['index_specs'],
[{'fields': [('_types', 1), ('addDate', -1)]},
{'fields': [('tags', 1)]},
{'fields': [('_types', 1), ('category', 1),
('addDate', -1)]}])
BlogPost.drop_collection() BlogPost.drop_collection()
info = BlogPost.objects._collection.index_information() info = BlogPost.objects._collection.index_information()
@@ -657,6 +693,13 @@ class DocumentTest(unittest.TestCase):
title = StringField() title = StringField()
meta = {'indexes': ['title']} meta = {'indexes': ['title']}
self.assertEqual(ExtendedBlogPost._meta['index_specs'],
[{'fields': [('_types', 1), ('addDate', -1)]},
{'fields': [('tags', 1)]},
{'fields': [('_types', 1), ('category', 1),
('addDate', -1)]},
{'fields': [('_types', 1), ('title', 1)]}])
BlogPost.drop_collection() BlogPost.drop_collection()
list(ExtendedBlogPost.objects) list(ExtendedBlogPost.objects)
@@ -687,6 +730,27 @@ class DocumentTest(unittest.TestCase):
description = StringField() description = StringField()
self.assertEqual(A._meta['index_specs'], B._meta['index_specs']) self.assertEqual(A._meta['index_specs'], B._meta['index_specs'])
self.assertEqual([{'fields': [('_types', 1), ('title', 1)]}],
A._meta['index_specs'])
def test_build_index_spec_is_not_destructive(self):
class MyDoc(Document):
keywords = StringField()
meta = {
'indexes': ['keywords'],
'allow_inheritance': False
}
self.assertEqual(MyDoc._meta['index_specs'],
[{'fields': [('keywords', 1)]}])
# Force index creation
MyDoc.objects._ensure_indexes()
self.assertEqual(MyDoc._meta['index_specs'],
[{'fields': [('keywords', 1)]}])
def test_db_field_load(self): def test_db_field_load(self):
"""Ensure we load data correctly """Ensure we load data correctly
@@ -748,6 +812,9 @@ class DocumentTest(unittest.TestCase):
'allow_inheritance': False 'allow_inheritance': False
} }
self.assertEqual([{'fields': [('rank.title', 1)]}],
Person._meta['index_specs'])
Person.drop_collection() Person.drop_collection()
# Indexes are lazy so use list() to perform query # Indexes are lazy so use list() to perform query
@@ -766,6 +833,10 @@ class DocumentTest(unittest.TestCase):
'*location.point', '*location.point',
], ],
} }
self.assertEqual([{'fields': [('location.point', '2d')]}],
Place._meta['index_specs'])
Place.drop_collection() Place.drop_collection()
info = Place.objects._collection.index_information() info = Place.objects._collection.index_information()
@@ -791,6 +862,10 @@ class DocumentTest(unittest.TestCase):
], ],
} }
self.assertEqual([{'fields': [('addDate', -1)], 'unique': True,
'sparse': True, 'types': False}],
BlogPost._meta['index_specs'])
BlogPost.drop_collection() BlogPost.drop_collection()
info = BlogPost.objects._collection.index_information() info = BlogPost.objects._collection.index_information()

View File

@@ -7,7 +7,7 @@ import tempfile
from decimal import Decimal from decimal import Decimal
from bson import Binary, DBRef from bson import Binary, DBRef, ObjectId
import gridfs import gridfs
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
@@ -1104,7 +1104,7 @@ class FieldTest(unittest.TestCase):
p = Person.objects.get(name="Ross") p = Person.objects.get(name="Ross")
self.assertEqual(p.parent, p1) self.assertEqual(p.parent, p1)
def test_str_reference_fields(self): def test_objectid_reference_fields(self):
class Person(Document): class Person(Document):
name = StringField() name = StringField()
@@ -1117,7 +1117,7 @@ class FieldTest(unittest.TestCase):
col = Person._get_collection() col = Person._get_collection()
data = col.find_one({'name': 'Ross'}) data = col.find_one({'name': 'Ross'})
self.assertEqual(data['parent'], "%s" % p1.pk) self.assertEqual(data['parent'], p1.pk)
p = Person.objects.get(name="Ross") p = Person.objects.get(name="Ross")
self.assertEqual(p.parent, p1) self.assertEqual(p.parent, p1)