diff --git a/docs/guide/defining-documents.rst b/docs/guide/defining-documents.rst index 3c276869..7b8dcd5b 100644 --- a/docs/guide/defining-documents.rst +++ b/docs/guide/defining-documents.rst @@ -46,6 +46,12 @@ are as follows: * :class:`~mongoengine.EmbeddedDocumentField` * :class:`~mongoengine.ReferenceField` * :class:`~mongoengine.GenericReferenceField` +* :class:`~mongoengine.BooleanField` +* :class:`~mongoengine.GeoLocationField` +* :class:`~mongoengine.FileField` +* :class:`~mongoengine.EmailField` +* :class:`~mongoengine.SortedListField` +* :class:`~mongoengine.BinaryField` Field arguments --------------- diff --git a/mongoengine/base.py b/mongoengine/base.py index c8c162b4..b6d5a63b 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -24,8 +24,8 @@ class BaseField(object): _index_with_types = True def __init__(self, db_field=None, name=None, required=False, default=None, - unique=False, unique_with=None, primary_key=False, validation=None, - choices=None): + unique=False, unique_with=None, primary_key=False, + validation=None, choices=None): self.db_field = (db_field or name) if not primary_key else '_id' if name: import warnings @@ -86,13 +86,15 @@ class BaseField(object): # check choices if self.choices is not None: if value not in self.choices: - raise ValidationError("Value must be one of %s."%unicode(self.choices)) + raise ValidationError("Value must be one of %s." + % unicode(self.choices)) # check validation argument if self.validation is not None: if callable(self.validation): if not self.validation(value): - raise ValidationError('Value does not match custom validation method.') + raise ValidationError('Value does not match custom' \ + 'validation method.') else: raise ValueError('validation argument must be a callable.') diff --git a/mongoengine/fields.py b/mongoengine/fields.py index 5893049d..ebefbb75 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -530,17 +530,21 @@ class GridFSProxy(object): def __init__(self): self.fs = gridfs.GridFS(_get_db()) # Filesystem instance - self.newfile = None # Used for partial writes + self.newfile = None # Used for partial writes self.grid_id = None # Store GridFS id for file def __getattr__(self, name): - obj = self.fs.get(self.grid_id) + obj = self.get() if name in dir(obj): return getattr(obj, name) def __get__(self, instance, value): return self + def get(self, id=None): + try: return self.fs.get(id or self.grid_id) + except: return None # File has been deleted + def new_file(self, **kwargs): self.newfile = self.fs.new_file(**kwargs) self.grid_id = self.newfile._id @@ -561,11 +565,17 @@ class GridFSProxy(object): self.newfile.writelines(lines) def read(self): - return self.fs.get(self.grid_id).read() + try: return self.get().read() + except: return None def delete(self): - # Delete file from GridFS + # Delete file from GridFS, FileField still remains self.fs.delete(self.grid_id) + self.grid_id = None + + def replace(self, file, **kwargs): + self.delete() + self.put(file, **kwargs) def close(self): if self.newfile: @@ -601,7 +611,7 @@ class FileField(BaseField): def to_python(self, value): # Use stored value (id) to lookup file in GridFS - return self.gridfs.fs.get(value) + return self.gridfs.get() def validate(self, value): assert isinstance(value, GridFSProxy) diff --git a/tests/fields.py b/tests/fields.py index e22e6ddd..8dddcb3e 100644 --- a/tests/fields.py +++ b/tests/fields.py @@ -649,7 +649,10 @@ class FieldTest(unittest.TestCase): self.assertTrue(streamfile == result) self.assertEquals(result.file.read(), text + more_text) self.assertEquals(result.file.content_type, content_type) - result.file.delete() # Remove file from GridFS + result.file.delete() + + # Ensure deleted file returns None + self.assertTrue(result.file.read() == None) setfile = SetFile() setfile.file = text @@ -658,7 +661,15 @@ class FieldTest(unittest.TestCase): result = SetFile.objects.first() self.assertTrue(setfile == result) self.assertEquals(result.file.read(), text) - result.file.delete() # Remove file from GridFS + + # Try replacing file with new one + result.file.replace(more_text) + result.save() + result.validate() + result = SetFile.objects.first() + self.assertTrue(setfile == result) + self.assertEquals(result.file.read(), more_text) + result.file.delete() PutFile.drop_collection() StreamFile.drop_collection()