Added ComplexBaseField

* Handles the efficient lazy dereferencing of DBrefs.
* Handles complex nested values in ListFields and DictFields
* Allows for both strictly declared ListFields and DictFields where the embedded
value must be of a field type or no restrictions where the values can be a mix
of field types / values.
* Handles DBrefences of documents where allow_inheritance = False.
This commit is contained in:
Ross Lawley
2011-06-06 17:21:54 +01:00
parent 602d7dad00
commit 4b9bacf731
5 changed files with 555 additions and 199 deletions

View File

@@ -549,11 +549,12 @@ class QuerySet(object):
parts = [parts]
fields = []
field = None
for field_name in parts:
# Handle ListField indexing:
if field_name.isdigit():
try:
field = field.field
new_field = field.field
except AttributeError, err:
raise InvalidQueryError(
"Can't use index on unsubscriptable field (%s)" % err)
@@ -567,11 +568,17 @@ class QuerySet(object):
field = document._fields[field_name]
else:
# Look up subfield on the previous field
field = field.lookup_member(field_name)
if field is None:
new_field = field.lookup_member(field_name)
from base import ComplexBaseField
if not new_field and isinstance(field, ComplexBaseField):
fields.append(field_name)
continue
elif not new_field:
raise InvalidQueryError('Cannot resolve field "%s"'
% field_name)
% field_name)
field = new_field # update field to the new field type
fields.append(field)
return fields
@classmethod
@@ -615,14 +622,33 @@ class QuerySet(object):
if _doc_cls:
# Switch field names to proper names [set in Field(name='foo')]
fields = QuerySet._lookup_field(_doc_cls, parts)
parts = [field.db_field for field in fields]
parts = []
cleaned_fields = []
append_field = True
for field in fields:
if isinstance(field, str):
parts.append(field)
append_field = False
else:
parts.append(field.db_field)
if append_field:
cleaned_fields.append(field)
# Convert value to proper value
field = fields[-1]
field = cleaned_fields[-1]
singular_ops = [None, 'ne', 'gt', 'gte', 'lt', 'lte', 'not']
singular_ops += match_operators
if op in singular_ops:
value = field.prepare_query_value(op, value)
if isinstance(field, basestring):
if op in match_operators and isinstance(value, basestring):
from mongoengine import StringField
value = StringField().prepare_query_value(op, value)
else:
value = field
else:
value = field.prepare_query_value(op, value)
elif op in ('in', 'nin', 'all', 'near'):
# 'in', 'nin' and 'all' require a list of values
value = [field.prepare_query_value(op, v) for v in value]
@@ -1170,14 +1196,19 @@ class QuerySet(object):
fields = QuerySet._lookup_field(_doc_cls, parts)
parts = []
cleaned_fields = []
append_field = True
for field in fields:
if isinstance(field, str):
parts.append(field)
append_field = False
else:
parts.append(field.db_field)
if append_field:
cleaned_fields.append(field)
# Convert value to proper value
field = fields[-1]
field = cleaned_fields[-1]
if op in (None, 'set', 'push', 'pull', 'addToSet'):
value = field.prepare_query_value(op, value)