Squashed commit of the following:
commit 48f988acd728f1193b57df8cf6b0154d69c15099 Merge: 6526923 1304f27 Author: Ross Lawley <ross.lawley@gmail.com> Date: Thu Jul 26 08:17:45 2012 -0700 Merge pull request #44 from faulkner/fix-notes Proper syntax for RST notes (so they actually render). commit 6526923345efd768044c4fba770a8a3ada161a40 Author: Ross Lawley <ross.lawley@gmail.com> Date: Thu Jul 26 16:00:32 2012 +0100 Fixed recursion loading bug in _get_changed_fields fixes hmarr/mongoengine#548 commit 24fd1acce68341361331e033d1692d61a936f871 Author: Ross Lawley <ross.lawley@gmail.com> Date: Thu Jul 26 14:14:10 2012 +0100 Version bump commit cbb9235dc5d863ee0bb8a315c976581e71b6a641 Merge: 6459d4c 19ec2c9 Author: Ross Lawley <ross.lawley@gmail.com> Date: Wed Jul 25 15:12:34 2012 +0100 Merge branch 'master' of github.com:hmarr/mongoengine commit 19ec2c9bc98db454680e681373f3fcd3b0f79a6c Merge: 3070e0b 601f0eb Author: Ross Lawley <ross.lawley@gmail.com> Date: Wed Jul 25 07:12:07 2012 -0700 Merge pull request #545 from maxcountryman/patch-1 Correcting typo in DynamicField docstring commit 6459d4c0b60229edcd4d562898833f221d00ebf4 Author: Ross Lawley <ross.lawley@gmail.com> Date: Wed Jul 25 14:55:10 2012 +0100 Fixed issue with custom queryset manager expecting explict variable names If using / expecting kwargs you have to call the queryset manager explicitly. commit 1304f2721f7850b223950edb85ec7c141255176c Author: Chris Faulkner <thefaulkner@gmail.com> Date: Tue Jul 24 14:06:43 2012 -0700 Proper syntax for RST notes (so they actually render). commit 598ffd3e5c107990dd41995d0bbb21bf13f67fb5 Author: Ross Lawley <ross.lawley@gmail.com> Date: Mon Jul 23 15:32:02 2012 +0100 Fixed documentation commit 601f0eb1682ebd9c9eb67f1b68b76bdd2cf3d8c7 Author: Max Countryman <maxc@me.com> Date: Fri Jul 20 19:12:43 2012 -0700 Correcting typo in DynamicField docstring
This commit is contained in:
parent
1a4533a9cf
commit
3628a7653c
@ -3,6 +3,14 @@ Changelog
|
|||||||
=========
|
=========
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.6.18
|
||||||
|
=================
|
||||||
|
- Fixed recursion loading bug in _get_changed_fields
|
||||||
|
|
||||||
|
Changes in 0.6.17
|
||||||
|
=================
|
||||||
|
- Fixed issue with custom queryset manager expecting explict variable names
|
||||||
|
|
||||||
Changes in 0.6.16
|
Changes in 0.6.16
|
||||||
=================
|
=================
|
||||||
- Fixed issue where db_alias wasn't inherited
|
- Fixed issue where db_alias wasn't inherited
|
||||||
@ -27,7 +35,7 @@ Changes in 0.6.14
|
|||||||
- Added support for add_to_set and each
|
- Added support for add_to_set and each
|
||||||
|
|
||||||
Changes in 0.6.13
|
Changes in 0.6.13
|
||||||
================
|
=================
|
||||||
- Fixed EmbeddedDocument db_field validation issue
|
- Fixed EmbeddedDocument db_field validation issue
|
||||||
- Fixed StringField unicode issue
|
- Fixed StringField unicode issue
|
||||||
- Fixes __repr__ modifying the cursor
|
- Fixes __repr__ modifying the cursor
|
||||||
|
@ -259,6 +259,35 @@ as the constructor's argument::
|
|||||||
content = StringField()
|
content = StringField()
|
||||||
|
|
||||||
|
|
||||||
|
.. _one-to-many-with-listfields:
|
||||||
|
|
||||||
|
One to Many with ListFields
|
||||||
|
'''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
If you are implementing a one to many relationship via a list of references,
|
||||||
|
then the references are stored as DBRefs and to query you need to pass an
|
||||||
|
instance of the object to the query::
|
||||||
|
|
||||||
|
class User(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class Page(Document):
|
||||||
|
content = StringField()
|
||||||
|
authors = ListField(ReferenceField(User))
|
||||||
|
|
||||||
|
bob = User(name="Bob Jones").save()
|
||||||
|
john = User(name="John Smith").save()
|
||||||
|
|
||||||
|
Page(content="Test Page", authors=[bob, john]).save()
|
||||||
|
Page(content="Another Page", authors=[john]).save()
|
||||||
|
|
||||||
|
# Find all pages Bob authored
|
||||||
|
Page.objects(authors__in=[bob])
|
||||||
|
|
||||||
|
# Find all pages that both Bob and John have authored
|
||||||
|
Page.objects(authors__all=[bob, john])
|
||||||
|
|
||||||
|
|
||||||
Dealing with deletion of referred documents
|
Dealing with deletion of referred documents
|
||||||
'''''''''''''''''''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''''''''''''''''''
|
||||||
By default, MongoDB doesn't check the integrity of your data, so deleting
|
By default, MongoDB doesn't check the integrity of your data, so deleting
|
||||||
|
@ -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, 6, 16)
|
VERSION = (0, 6, 18)
|
||||||
|
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
|
@ -1017,9 +1017,10 @@ Invalid data to create a `%s` instance.\n%s""".strip() % (cls._class_name, error
|
|||||||
field_list.update(self._dynamic_fields)
|
field_list.update(self._dynamic_fields)
|
||||||
|
|
||||||
for field_name in field_list:
|
for field_name in field_list:
|
||||||
|
|
||||||
db_field_name = self._db_field_map.get(field_name, field_name)
|
db_field_name = self._db_field_map.get(field_name, field_name)
|
||||||
key = '%s.' % db_field_name
|
key = '%s.' % db_field_name
|
||||||
field = getattr(self, field_name, None)
|
field = self._data.get(field_name, None)
|
||||||
if hasattr(field, 'id'):
|
if hasattr(field, 'id'):
|
||||||
if field.id in inspected:
|
if field.id in inspected:
|
||||||
continue
|
continue
|
||||||
|
@ -375,7 +375,7 @@ class DynamicDocument(Document):
|
|||||||
:class:`~mongoengine.DynamicField` and data can be attributed to that
|
:class:`~mongoengine.DynamicField` and data can be attributed to that
|
||||||
field.
|
field.
|
||||||
|
|
||||||
..note::
|
.. note::
|
||||||
|
|
||||||
There is one caveat on Dynamic Documents: fields cannot start with `_`
|
There is one caveat on Dynamic Documents: fields cannot start with `_`
|
||||||
"""
|
"""
|
||||||
|
@ -169,7 +169,7 @@ class IntField(BaseField):
|
|||||||
def prepare_query_value(self, op, value):
|
def prepare_query_value(self, op, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return int(value)
|
return int(value)
|
||||||
|
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ class FloatField(BaseField):
|
|||||||
def prepare_query_value(self, op, value):
|
def prepare_query_value(self, op, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return float(value)
|
return float(value)
|
||||||
|
|
||||||
|
|
||||||
@ -451,7 +451,7 @@ class GenericEmbeddedDocumentField(BaseField):
|
|||||||
|
|
||||||
Only valid values are subclasses of :class:`~mongoengine.EmbeddedDocument`.
|
Only valid values are subclasses of :class:`~mongoengine.EmbeddedDocument`.
|
||||||
|
|
||||||
..note :: You can use the choices param to limit the acceptable
|
.. note:: You can use the choices param to limit the acceptable
|
||||||
EmbeddedDocument types
|
EmbeddedDocument types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -483,7 +483,7 @@ class GenericEmbeddedDocumentField(BaseField):
|
|||||||
|
|
||||||
|
|
||||||
class DynamicField(BaseField):
|
class DynamicField(BaseField):
|
||||||
"""A tryly dynamic field type capable of handling different and varying
|
"""A truly dynamic field type capable of handling different and varying
|
||||||
types of data.
|
types of data.
|
||||||
|
|
||||||
Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data"""
|
Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data"""
|
||||||
@ -530,6 +530,8 @@ class ListField(ComplexBaseField):
|
|||||||
"""A list field that wraps a standard field, allowing multiple instances
|
"""A list field that wraps a standard field, allowing multiple instances
|
||||||
of the field to be used as a list in the database.
|
of the field to be used as a list in the database.
|
||||||
|
|
||||||
|
If using with ReferenceFields see: :ref:`one-to-many-with-listfields`
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Required means it cannot be empty - as the default for ListFields is []
|
Required means it cannot be empty - as the default for ListFields is []
|
||||||
"""
|
"""
|
||||||
@ -766,10 +768,10 @@ class GenericReferenceField(BaseField):
|
|||||||
"""A reference to *any* :class:`~mongoengine.document.Document` subclass
|
"""A reference to *any* :class:`~mongoengine.document.Document` subclass
|
||||||
that will be automatically dereferenced on access (lazily).
|
that will be automatically dereferenced on access (lazily).
|
||||||
|
|
||||||
..note :: Any documents used as a generic reference must be registered in the
|
.. note:: Any documents used as a generic reference must be registered in the
|
||||||
document registry. Importing the model will automatically register it.
|
document registry. Importing the model will automatically register it.
|
||||||
|
|
||||||
..note :: You can use the choices param to limit the acceptable Document types
|
.. note:: You can use the choices param to limit the acceptable Document types
|
||||||
|
|
||||||
.. versionadded:: 0.3
|
.. versionadded:: 0.3
|
||||||
"""
|
"""
|
||||||
|
@ -806,9 +806,9 @@ class QuerySet(object):
|
|||||||
keyword argument called :attr:`defaults`.
|
keyword argument called :attr:`defaults`.
|
||||||
|
|
||||||
.. note:: This requires two separate operations and therefore a
|
.. note:: This requires two separate operations and therefore a
|
||||||
race condition exists. Because there are no transactions in mongoDB
|
race condition exists. Because there are no transactions in mongoDB
|
||||||
other approaches should be investigated, to ensure you don't
|
other approaches should be investigated, to ensure you don't
|
||||||
accidently duplicate data when using this method.
|
accidently duplicate data when using this method.
|
||||||
|
|
||||||
:param write_options: optional extra keyword arguments used if we
|
:param write_options: optional extra keyword arguments used if we
|
||||||
have to create a new document.
|
have to create a new document.
|
||||||
@ -816,8 +816,8 @@ class QuerySet(object):
|
|||||||
|
|
||||||
:param auto_save: if the object is to be saved automatically if not found.
|
:param auto_save: if the object is to be saved automatically if not found.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.6 - added `auto_save`
|
||||||
.. versionadded:: 0.3
|
.. versionadded:: 0.3
|
||||||
.. versionupdated:: 0.6 - added `auto_save`
|
|
||||||
"""
|
"""
|
||||||
defaults = query.get('defaults', {})
|
defaults = query.get('defaults', {})
|
||||||
if 'defaults' in query:
|
if 'defaults' in query:
|
||||||
@ -1882,9 +1882,9 @@ class QuerySetManager(object):
|
|||||||
queryset = queryset_class(owner, owner._get_collection())
|
queryset = queryset_class(owner, owner._get_collection())
|
||||||
if self.get_queryset:
|
if self.get_queryset:
|
||||||
var_names = self.get_queryset.func_code.co_varnames
|
var_names = self.get_queryset.func_code.co_varnames
|
||||||
if var_names == ('queryset',):
|
if len(var_names) == 1:
|
||||||
queryset = self.get_queryset(queryset)
|
queryset = self.get_queryset(queryset)
|
||||||
elif var_names == ('doc_cls', 'queryset',):
|
elif len(var_names) == 2:
|
||||||
queryset = self.get_queryset(owner, queryset)
|
queryset = self.get_queryset(owner, queryset)
|
||||||
else:
|
else:
|
||||||
queryset = partial(self.get_queryset, owner, queryset)
|
queryset = partial(self.get_queryset, owner, queryset)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%define srcname mongoengine
|
%define srcname mongoengine
|
||||||
|
|
||||||
Name: python-%{srcname}
|
Name: python-%{srcname}
|
||||||
Version: 0.6.16
|
Version: 0.6.18
|
||||||
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
|
||||||
|
|
||||||
|
@ -579,6 +579,64 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
Blog.objects.insert([blog2, blog3], write_options={'continue_on_error': True})
|
Blog.objects.insert([blog2, blog3], write_options={'continue_on_error': True})
|
||||||
self.assertEqual(Blog.objects.count(), 3)
|
self.assertEqual(Blog.objects.count(), 3)
|
||||||
|
|
||||||
|
def test_get_changed_fields_query_count(self):
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
owns = ListField(ReferenceField('Organization'))
|
||||||
|
projects = ListField(ReferenceField('Project'))
|
||||||
|
|
||||||
|
class Organization(Document):
|
||||||
|
name = StringField()
|
||||||
|
owner = ReferenceField('Person')
|
||||||
|
employees = ListField(ReferenceField('Person'))
|
||||||
|
|
||||||
|
class Project(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
Organization.drop_collection()
|
||||||
|
Project.drop_collection()
|
||||||
|
|
||||||
|
r1 = Project(name="r1").save()
|
||||||
|
r2 = Project(name="r2").save()
|
||||||
|
r3 = Project(name="r3").save()
|
||||||
|
p1 = Person(name="p1", projects=[r1, r2]).save()
|
||||||
|
p2 = Person(name="p2", projects=[r2]).save()
|
||||||
|
o1 = Organization(name="o1", employees=[p1]).save()
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
self.assertEqual(q, 0)
|
||||||
|
|
||||||
|
fresh_o1 = Organization.objects.get(id=o1.id)
|
||||||
|
self.assertEqual(1, q)
|
||||||
|
fresh_o1._get_changed_fields()
|
||||||
|
self.assertEqual(1, q)
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
self.assertEqual(q, 0)
|
||||||
|
|
||||||
|
fresh_o1 = Organization.objects.get(id=o1.id)
|
||||||
|
fresh_o1.save()
|
||||||
|
|
||||||
|
self.assertEquals(q, 2)
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
self.assertEqual(q, 0)
|
||||||
|
|
||||||
|
fresh_o1 = Organization.objects.get(id=o1.id)
|
||||||
|
fresh_o1.save(cascade=False)
|
||||||
|
|
||||||
|
self.assertEquals(q, 2)
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
self.assertEqual(q, 0)
|
||||||
|
|
||||||
|
fresh_o1 = Organization.objects.get(id=o1.id)
|
||||||
|
fresh_o1.employees.append(p2)
|
||||||
|
fresh_o1.save(cascade=False)
|
||||||
|
|
||||||
|
self.assertEquals(q, 3)
|
||||||
|
|
||||||
def test_slave_okay(self):
|
def test_slave_okay(self):
|
||||||
"""Ensures that a query can take slave_okay syntax
|
"""Ensures that a query can take slave_okay syntax
|
||||||
@ -2228,28 +2286,28 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
date = DateTimeField(default=datetime.now)
|
date = DateTimeField(default=datetime.now)
|
||||||
|
|
||||||
@queryset_manager
|
@queryset_manager
|
||||||
def objects(doc_cls, queryset):
|
def objects(cls, qryset):
|
||||||
return queryset(deleted=False)
|
return qryset(deleted=False)
|
||||||
|
|
||||||
@queryset_manager
|
@queryset_manager
|
||||||
def music_posts(doc_cls, queryset):
|
def music_posts(doc_cls, queryset, deleted=False):
|
||||||
return queryset(tags='music', deleted=False).order_by('-date')
|
return queryset(tags='music',
|
||||||
|
deleted=deleted).order_by('date')
|
||||||
|
|
||||||
BlogPost.drop_collection()
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
post1 = BlogPost(tags=['music', 'film'])
|
post1 = BlogPost(tags=['music', 'film']).save()
|
||||||
post1.save()
|
post2 = BlogPost(tags=['music']).save()
|
||||||
post2 = BlogPost(tags=['music'])
|
post3 = BlogPost(tags=['film', 'actors']).save()
|
||||||
post2.save()
|
post4 = BlogPost(tags=['film', 'actors', 'music'], deleted=True).save()
|
||||||
post3 = BlogPost(tags=['film', 'actors'])
|
|
||||||
post3.save()
|
|
||||||
post4 = BlogPost(tags=['film', 'actors'], deleted=True)
|
|
||||||
post4.save()
|
|
||||||
|
|
||||||
self.assertEqual([p.id for p in BlogPost.objects],
|
self.assertEqual([p.id for p in BlogPost.objects()],
|
||||||
[post1.id, post2.id, post3.id])
|
[post1.id, post2.id, post3.id])
|
||||||
self.assertEqual([p.id for p in BlogPost.music_posts],
|
self.assertEqual([p.id for p in BlogPost.music_posts()],
|
||||||
[post2.id, post1.id])
|
[post1.id, post2.id])
|
||||||
|
|
||||||
|
self.assertEqual([p.id for p in BlogPost.music_posts(True)],
|
||||||
|
[post4.id])
|
||||||
|
|
||||||
BlogPost.drop_collection()
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user