Merge branch 'master' into mapreduce
This commit is contained in:
		
							
								
								
									
										3
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								AUTHORS
									
									
									
									
									
								
							@@ -1,3 +1,4 @@
 | 
				
			|||||||
Harry Marr <harry@tractiondigital>
 | 
					Harry Marr <harry@hmarr.com>
 | 
				
			||||||
Matt Dennewitz <mattdennewitz@gmail.com>
 | 
					Matt Dennewitz <mattdennewitz@gmail.com>
 | 
				
			||||||
Deepak Thukral <iapain@yahoo.com>
 | 
					Deepak Thukral <iapain@yahoo.com>
 | 
				
			||||||
 | 
					Florian Schlachter <flori@n-schlachter.de>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,8 @@ Fields
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. autoclass:: mongoengine.ListField
 | 
					.. autoclass:: mongoengine.ListField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. autoclass:: mongoengine.BinaryField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. autoclass:: mongoengine.ObjectIdField
 | 
					.. autoclass:: mongoengine.ObjectIdField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. autoclass:: mongoengine.ReferenceField
 | 
					.. autoclass:: mongoengine.ReferenceField
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,13 @@ fetch documents from the database::
 | 
				
			|||||||
    for user in User.objects:
 | 
					    for user in User.objects:
 | 
				
			||||||
        print user.name
 | 
					        print user.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. note::
 | 
				
			||||||
 | 
					   Once the iteration finishes (when :class:`StopIteration` is raised),
 | 
				
			||||||
 | 
					   :meth:`~mongoengine.queryset.QuerySet.rewind` will be called so that the
 | 
				
			||||||
 | 
					   :class:`~mongoengine.queryset.QuerySet` may be iterated over again. The
 | 
				
			||||||
 | 
					   results of the first iteration are *not* cached, so the database will be hit
 | 
				
			||||||
 | 
					   each time the :class:`~mongoengine.queryset.QuerySet` is iterated over.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Filtering queries
 | 
					Filtering queries
 | 
				
			||||||
=================
 | 
					=================
 | 
				
			||||||
The query may be filtered by calling the
 | 
					The query may be filtered by calling the
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,7 +86,8 @@ class ObjectIdField(BaseField):
 | 
				
			|||||||
            try:
 | 
					            try:
 | 
				
			||||||
                return pymongo.objectid.ObjectId(str(value))
 | 
					                return pymongo.objectid.ObjectId(str(value))
 | 
				
			||||||
            except Exception, e:
 | 
					            except Exception, e:
 | 
				
			||||||
                raise ValidationError(e.message)
 | 
					                #e.message attribute has been deprecated since Python 2.6
 | 
				
			||||||
 | 
					                raise ValidationError(str(e))
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def prepare_query_value(self, op, value):
 | 
					    def prepare_query_value(self, op, value):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@ class User(Document):
 | 
				
			|||||||
    is_active = BooleanField(default=True)
 | 
					    is_active = BooleanField(default=True)
 | 
				
			||||||
    is_superuser = BooleanField(default=False)
 | 
					    is_superuser = BooleanField(default=False)
 | 
				
			||||||
    last_login = DateTimeField(default=datetime.datetime.now)
 | 
					    last_login = DateTimeField(default=datetime.datetime.now)
 | 
				
			||||||
 | 
					    date_joined = DateTimeField(default=datetime.datetime.now)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_full_name(self):
 | 
					    def get_full_name(self):
 | 
				
			||||||
        """Returns the users first and last names, separated by a space.
 | 
					        """Returns the users first and last names, separated by a space.
 | 
				
			||||||
@@ -70,7 +71,20 @@ class User(Document):
 | 
				
			|||||||
        """Create (and save) a new user with the given username, password and
 | 
					        """Create (and save) a new user with the given username, password and
 | 
				
			||||||
        email address.
 | 
					        email address.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        user = User(username=username, email=email)
 | 
					        now = datetime.datetime.now()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Normalize the address by lowercasing the domain part of the email
 | 
				
			||||||
 | 
					        # address.
 | 
				
			||||||
 | 
					        # Not sure why we'r allowing null email when its not allowed in django
 | 
				
			||||||
 | 
					        if email is not None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                email_name, domain_part = email.strip().split('@', 1)
 | 
				
			||||||
 | 
					            except ValueError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                email = '@'.join([email_name, domain_part.lower()])
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        user = User(username=username, email=email, date_joined=now)
 | 
				
			||||||
        user.set_password(password)
 | 
					        user.set_password(password)
 | 
				
			||||||
        user.save()
 | 
					        user.save()
 | 
				
			||||||
        return user
 | 
					        return user
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,8 @@ import decimal
 | 
				
			|||||||
__all__ = ['StringField', 'IntField', 'FloatField', 'BooleanField',
 | 
					__all__ = ['StringField', 'IntField', 'FloatField', 'BooleanField',
 | 
				
			||||||
           'DateTimeField', 'EmbeddedDocumentField', 'ListField', 'DictField',
 | 
					           'DateTimeField', 'EmbeddedDocumentField', 'ListField', 'DictField',
 | 
				
			||||||
           'ObjectIdField', 'ReferenceField', 'ValidationError',
 | 
					           'ObjectIdField', 'ReferenceField', 'ValidationError',
 | 
				
			||||||
           'DecimalField', 'URLField', 'GenericReferenceField']
 | 
					           'DecimalField', 'URLField', 'GenericReferenceField',
 | 
				
			||||||
 | 
					           'BinaryField']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RECURSIVE_REFERENCE_CONSTANT = 'self'
 | 
					RECURSIVE_REFERENCE_CONSTANT = 'self'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -442,3 +443,23 @@ class GenericReferenceField(BaseField):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def prepare_query_value(self, op, value):
 | 
					    def prepare_query_value(self, op, value):
 | 
				
			||||||
        return self.to_mongo(value)['_ref']
 | 
					        return self.to_mongo(value)['_ref']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BinaryField(BaseField):
 | 
				
			||||||
 | 
					    """A binary data field.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, max_bytes=None, **kwargs):
 | 
				
			||||||
 | 
					        self.max_bytes = max_bytes
 | 
				
			||||||
 | 
					        super(BinaryField, self).__init__(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def to_mongo(self, value):
 | 
				
			||||||
 | 
					        return pymongo.binary.Binary(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def to_python(self, value):
 | 
				
			||||||
 | 
					        return str(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate(self, value):
 | 
				
			||||||
 | 
					        assert isinstance(value, str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.max_bytes is not None and len(value) > self.max_bytes:
 | 
				
			||||||
 | 
					            raise ValidationError('Binary value is too long')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -418,9 +418,18 @@ class QuerySet(object):
 | 
				
			|||||||
    def next(self):
 | 
					    def next(self):
 | 
				
			||||||
        """Wrap the result in a :class:`~mongoengine.Document` object.
 | 
					        """Wrap the result in a :class:`~mongoengine.Document` object.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if self._limit == 0:
 | 
					        try:
 | 
				
			||||||
            raise StopIteration
 | 
					            if self._limit == 0:
 | 
				
			||||||
        return self._document._from_son(self._cursor.next())
 | 
					                raise StopIteration
 | 
				
			||||||
 | 
					            return self._document._from_son(self._cursor.next())
 | 
				
			||||||
 | 
					        except StopIteration, e:
 | 
				
			||||||
 | 
					            self.rewind()
 | 
				
			||||||
 | 
					            raise e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rewind(self):
 | 
				
			||||||
 | 
					        """Rewind the cursor to its unevaluated state.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self._cursor.rewind()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def count(self):
 | 
					    def count(self):
 | 
				
			||||||
        """Count the selected elements in the query.
 | 
					        """Count the selected elements in the query.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -495,6 +495,61 @@ class FieldTest(unittest.TestCase):
 | 
				
			|||||||
        Post.drop_collection()
 | 
					        Post.drop_collection()
 | 
				
			||||||
        User.drop_collection()
 | 
					        User.drop_collection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_binary_fields(self):
 | 
				
			||||||
 | 
					        """Ensure that binary fields can be stored and retrieved.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        class Attachment(Document):
 | 
				
			||||||
 | 
					            content_type = StringField()
 | 
				
			||||||
 | 
					            blob = BinaryField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        BLOB = '\xe6\x00\xc4\xff\x07'
 | 
				
			||||||
 | 
					        MIME_TYPE = 'application/octet-stream'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Attachment.drop_collection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attachment = Attachment(content_type=MIME_TYPE, blob=BLOB)
 | 
				
			||||||
 | 
					        attachment.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attachment_1 = Attachment.objects().first()
 | 
				
			||||||
 | 
					        self.assertEqual(MIME_TYPE, attachment_1.content_type)
 | 
				
			||||||
 | 
					        self.assertEqual(BLOB, attachment_1.blob)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Attachment.drop_collection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_binary_validation(self):
 | 
				
			||||||
 | 
					        """Ensure that invalid values cannot be assigned to binary fields.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        class Attachment(Document):
 | 
				
			||||||
 | 
					            blob = BinaryField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class AttachmentRequired(Document):
 | 
				
			||||||
 | 
					            blob = BinaryField(required=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class AttachmentSizeLimit(Document):
 | 
				
			||||||
 | 
					            blob = BinaryField(max_bytes=4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Attachment.drop_collection()
 | 
				
			||||||
 | 
					        AttachmentRequired.drop_collection()
 | 
				
			||||||
 | 
					        AttachmentSizeLimit.drop_collection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attachment = Attachment()
 | 
				
			||||||
 | 
					        attachment.validate()
 | 
				
			||||||
 | 
					        attachment.blob = 2
 | 
				
			||||||
 | 
					        self.assertRaises(ValidationError, attachment.validate)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attachment_required = AttachmentRequired()
 | 
				
			||||||
 | 
					        self.assertRaises(ValidationError, attachment_required.validate)
 | 
				
			||||||
 | 
					        attachment_required.blob = '\xe6\x00\xc4\xff\x07'
 | 
				
			||||||
 | 
					        attachment_required.validate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attachment_size_limit = AttachmentSizeLimit(blob='\xe6\x00\xc4\xff\x07')
 | 
				
			||||||
 | 
					        self.assertRaises(ValidationError, attachment_size_limit.validate)
 | 
				
			||||||
 | 
					        attachment_size_limit.blob = '\xe6\x00\xc4\xff'
 | 
				
			||||||
 | 
					        attachment_size_limit.validate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Attachment.drop_collection()
 | 
				
			||||||
 | 
					        AttachmentRequired.drop_collection()
 | 
				
			||||||
 | 
					        AttachmentSizeLimit.drop_collection()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    unittest.main()
 | 
					    unittest.main()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,6 +189,18 @@ class QuerySetTest(unittest.TestCase):
 | 
				
			|||||||
        person = self.Person.objects.get(age=50)
 | 
					        person = self.Person.objects.get(age=50)
 | 
				
			||||||
        self.assertEqual(person.name, "User C")
 | 
					        self.assertEqual(person.name, "User C")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_repeated_iteration(self):
 | 
				
			||||||
 | 
					        """Ensure that QuerySet rewinds itself one iteration finishes.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.Person(name='Person 1').save()
 | 
				
			||||||
 | 
					        self.Person(name='Person 2').save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        queryset = self.Person.objects
 | 
				
			||||||
 | 
					        people1 = [person for person in queryset]
 | 
				
			||||||
 | 
					        people2 = [person for person in queryset]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(people1, people2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_regex_query_shortcuts(self):
 | 
					    def test_regex_query_shortcuts(self):
 | 
				
			||||||
        """Ensure that contains, startswith, endswith, etc work.
 | 
					        """Ensure that contains, startswith, endswith, etc work.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user