Compare commits
2 Commits
cleanup-qs
...
fix-904
Author | SHA1 | Date | |
---|---|---|---|
|
2d9e21f639 | ||
|
4631b75553 |
@@ -684,8 +684,13 @@ class BaseDocument(object):
|
||||
# class if unavailable
|
||||
class_name = son.get('_cls', cls._class_name)
|
||||
|
||||
# Convert SON to a dict, making sure each key is a string
|
||||
data = {str(key): value for key, value in son.iteritems()}
|
||||
# Convert SON to a data dict, making sure each key is a string and
|
||||
# corresponds to the right db field.
|
||||
data = {}
|
||||
for key, value in son.iteritems():
|
||||
key = str(key)
|
||||
key = cls._db_field_map.get(key, key)
|
||||
data[key] = value
|
||||
|
||||
# Return correct subclass for document type
|
||||
if class_name != cls._class_name:
|
||||
|
@@ -158,49 +158,44 @@ class BaseQuerySet(object):
|
||||
# self._cursor
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Return a document instance corresponding to a given index if
|
||||
the key is an integer. If the key is a slice, translate its
|
||||
bounds into a skip and a limit, and return a cloned queryset
|
||||
with that skip/limit applied. For example:
|
||||
|
||||
>>> User.objects[0]
|
||||
<User: User object>
|
||||
>>> User.objects[1:3]
|
||||
[<User: User object>, <User: User object>]
|
||||
"""
|
||||
"""Support skip and limit using getitem and slicing syntax."""
|
||||
queryset = self.clone()
|
||||
|
||||
# Handle a slice
|
||||
# Slice provided
|
||||
if isinstance(key, slice):
|
||||
queryset._cursor_obj = queryset._cursor[key]
|
||||
queryset._skip, queryset._limit = key.start, key.stop
|
||||
if key.start and key.stop:
|
||||
queryset._limit = key.stop - key.start
|
||||
|
||||
try:
|
||||
queryset._cursor_obj = queryset._cursor[key]
|
||||
queryset._skip, queryset._limit = key.start, key.stop
|
||||
if key.start and key.stop:
|
||||
queryset._limit = key.stop - key.start
|
||||
except IndexError as err:
|
||||
# PyMongo raises an error if key.start == key.stop, catch it,
|
||||
# bin it, kill it.
|
||||
start = key.start or 0
|
||||
if start >= 0 and key.stop >= 0 and key.step is None:
|
||||
if start == key.stop:
|
||||
queryset.limit(0)
|
||||
queryset._skip = key.start
|
||||
queryset._limit = key.stop - start
|
||||
return queryset
|
||||
raise err
|
||||
# Allow further QuerySet modifications to be performed
|
||||
return queryset
|
||||
|
||||
# Handle an index
|
||||
# Integer index provided
|
||||
elif isinstance(key, int):
|
||||
if queryset._scalar:
|
||||
return queryset._get_scalar(
|
||||
queryset._document._from_son(
|
||||
queryset._cursor[key],
|
||||
_auto_dereference=self._auto_dereference,
|
||||
only_fields=self.only_fields
|
||||
)
|
||||
)
|
||||
queryset._document._from_son(queryset._cursor[key],
|
||||
_auto_dereference=self._auto_dereference,
|
||||
only_fields=self.only_fields))
|
||||
|
||||
if queryset._as_pymongo:
|
||||
return queryset._get_as_pymongo(queryset._cursor[key])
|
||||
return queryset._document._from_son(queryset._cursor[key],
|
||||
_auto_dereference=self._auto_dereference,
|
||||
only_fields=self.only_fields)
|
||||
|
||||
return queryset._document._from_son(
|
||||
queryset._cursor[key],
|
||||
_auto_dereference=self._auto_dereference,
|
||||
only_fields=self.only_fields
|
||||
)
|
||||
|
||||
raise AttributeError('Provide a slice or an integer index')
|
||||
raise AttributeError
|
||||
|
||||
def __iter__(self):
|
||||
raise NotImplementedError
|
||||
|
@@ -1173,14 +1173,6 @@ class FieldTest(MongoDBTestCase):
|
||||
post.reload()
|
||||
self.assertEqual(post.info, ['0', '1', '2', '3', 'a', '5'])
|
||||
|
||||
# __setitem__(index, value) with a negative index
|
||||
reset_post()
|
||||
post.info[-2] = 'a'
|
||||
self.assertEqual(post.info, ['0', '1', '2', '3', 'a', '5'])
|
||||
post.save()
|
||||
post.reload()
|
||||
self.assertEqual(post.info, ['0', '1', '2', '3', 'a', '5'])
|
||||
|
||||
# '__setitem__(slice(i, j), listB)'
|
||||
# aka 'listA[i:j] = listB'
|
||||
# aka 'setitem(listA, slice(i, j), listB)'
|
||||
@@ -1191,16 +1183,6 @@ class FieldTest(MongoDBTestCase):
|
||||
post.reload()
|
||||
self.assertEqual(post.info, ['0', 'h', 'e', 'l', 'l', 'o', '3', '4', '5'])
|
||||
|
||||
# '__setitem__(slice(i, j), listB)' with negative i and j
|
||||
reset_post()
|
||||
post.info[-5:-3] = ['h', 'e', 'l', 'l', 'o']
|
||||
self.assertEqual(post.info, ['0', 'h', 'e', 'l', 'l', 'o', '3', '4', '5'])
|
||||
post.save()
|
||||
post.reload()
|
||||
self.assertEqual(post.info, ['0', 'h', 'e', 'l', 'l', 'o', '3', '4', '5'])
|
||||
|
||||
# negative
|
||||
|
||||
# 'append'
|
||||
reset_post()
|
||||
post.info.append('h')
|
||||
@@ -1901,6 +1883,51 @@ class FieldTest(MongoDBTestCase):
|
||||
doc = self.db.test.find_one()
|
||||
self.assertEqual(doc['x']['i'], 2)
|
||||
|
||||
def test_double_embedded_db_field(self):
|
||||
"""Make sure multiple layers of embedded docs resolve db fields
|
||||
properly and can be initialized using dicts.
|
||||
"""
|
||||
class C(EmbeddedDocument):
|
||||
txt = StringField()
|
||||
|
||||
class B(EmbeddedDocument):
|
||||
c = EmbeddedDocumentField(C, db_field='fc')
|
||||
|
||||
class A(Document):
|
||||
b = EmbeddedDocumentField(B, db_field='fb')
|
||||
|
||||
a = A(
|
||||
b=B(
|
||||
c=C(txt='hi')
|
||||
)
|
||||
)
|
||||
a.validate()
|
||||
|
||||
a = A(b={'c': {'txt': 'hi'}})
|
||||
a.validate()
|
||||
|
||||
def test_double_embedded_db_field_from_son(self):
|
||||
"""Make sure multiple layers of embedded docs resolve db fields
|
||||
from SON properly.
|
||||
"""
|
||||
class C(EmbeddedDocument):
|
||||
txt = StringField()
|
||||
|
||||
class B(EmbeddedDocument):
|
||||
c = EmbeddedDocumentField(C, db_field='fc')
|
||||
|
||||
class A(Document):
|
||||
b = EmbeddedDocumentField(B, db_field='fb')
|
||||
|
||||
a = A._from_son(SON([
|
||||
('fb', SON([
|
||||
('fc', SON([
|
||||
('txt', 'hi')
|
||||
]))
|
||||
]))
|
||||
]))
|
||||
self.assertEqual(a.b.c.txt, 'hi')
|
||||
|
||||
def test_embedded_document_validation(self):
|
||||
"""Ensure that invalid embedded documents cannot be assigned to
|
||||
embedded document fields.
|
||||
|
Reference in New Issue
Block a user