first version of BC validation schema
This commit is contained in:
		| @@ -4,7 +4,6 @@ from queryset import DO_NOTHING | ||||
|  | ||||
| from mongoengine import signals | ||||
|  | ||||
| import weakref | ||||
| import sys | ||||
| import pymongo | ||||
| import pymongo.objectid | ||||
| @@ -19,9 +18,27 @@ class NotRegistered(Exception): | ||||
| class InvalidDocumentError(Exception): | ||||
|     pass | ||||
|  | ||||
| class ValidationError(Exception): | ||||
|     pass | ||||
|  | ||||
| class ValidationError(Exception): | ||||
|     errors = {} | ||||
|     field_name = None | ||||
|  | ||||
|     def __init__(self, message, **kwargs): | ||||
|         self.field_name = kwargs.get('field_name') | ||||
|         super(ValidationError, self).__init__(message) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.message | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return '%s(%s,)' % (self.__class__.__name__, self.message) | ||||
|  | ||||
|     def __getattribute__(self, name): | ||||
|         message = super(ValidationError, self).__getattribute__(name) | ||||
|         if name == 'message' and self.field_name: | ||||
|             return message + ' ("%s")' % self.field_name | ||||
|         else: | ||||
|             return message | ||||
|  | ||||
| _document_registry = {} | ||||
|  | ||||
| @@ -50,6 +67,8 @@ class BaseField(object): | ||||
|     .. versionchanged:: 0.5 - added verbose and help text | ||||
|     """ | ||||
|  | ||||
|     name = None | ||||
|  | ||||
|     # Fields may have _types inserted into indexes by default | ||||
|     _index_with_types = True | ||||
|     _geo_index = False | ||||
| @@ -116,6 +135,14 @@ class BaseField(object): | ||||
|         instance._data[self.name] = value | ||||
|         instance._mark_as_changed(self.name) | ||||
|  | ||||
|     def error(self, message, errors=None, field_name=None): | ||||
|         """Raises a ValidationError. | ||||
|         """ | ||||
|         field_name = field_name if field_name else self.name | ||||
|         error = ValidationError(message, field_name=field_name) | ||||
|         error.errors = errors if errors else {} | ||||
|         raise error | ||||
|  | ||||
|     def to_python(self, value): | ||||
|         """Convert a MongoDB-compatible type to a Python type. | ||||
|         """ | ||||
| @@ -141,15 +168,13 @@ class BaseField(object): | ||||
|         if self.choices is not None: | ||||
|             option_keys = [option_key for option_key, option_value in self.choices] | ||||
|             if value not in option_keys: | ||||
|                 raise ValidationError('Value must be one of %s ("%s")' % | ||||
|                                       (unicode(option_keys), self.name)) | ||||
|                 self.error('Value must be one of %s' % unicode(option_keys)) | ||||
|  | ||||
|         # 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 ("%s")' % self.name) | ||||
|                     self.error('Value does not match custom validation method') | ||||
|             else: | ||||
|                 raise ValueError('validation argument for "%s" must be a ' | ||||
|                                  'callable.' % self.name) | ||||
| @@ -197,7 +222,7 @@ class ComplexBaseField(BaseField): | ||||
|         if not hasattr(value, 'items'): | ||||
|             try: | ||||
|                 is_list = True | ||||
|                 value = dict([(k,v) for k,v in enumerate(value)]) | ||||
|                 value = dict([(k, v) for k, v in enumerate(value)]) | ||||
|             except TypeError:  # Not iterable return the value | ||||
|                 return value | ||||
|  | ||||
| @@ -205,13 +230,12 @@ class ComplexBaseField(BaseField): | ||||
|             value_dict = dict([(key, self.field.to_python(item)) for key, item in value.items()]) | ||||
|         else: | ||||
|             value_dict = {} | ||||
|             for k,v in value.items(): | ||||
|             for k, v in value.items(): | ||||
|                 if isinstance(v, Document): | ||||
|                     # We need the id from the saved object to create the DBRef | ||||
|                     if v.pk is None: | ||||
|                         raise ValidationError('You can only reference ' | ||||
|                                       'documents once they have been saved ' | ||||
|                                       'to the database ("%s")' % self.name) | ||||
|                         self.error('You can only reference documents once they' | ||||
|                                    ' have been saved to the database') | ||||
|                     collection = v._get_collection_name() | ||||
|                     value_dict[k] = pymongo.dbref.DBRef(collection, v.pk) | ||||
|                 elif hasattr(v, 'to_python'): | ||||
| @@ -220,7 +244,7 @@ class ComplexBaseField(BaseField): | ||||
|                     value_dict[k] = self.to_python(v) | ||||
|  | ||||
|         if is_list:  # Convert back to a list | ||||
|             return [v for k,v in sorted(value_dict.items(), key=operator.itemgetter(0))] | ||||
|             return [v for k, v in sorted(value_dict.items(), key=operator.itemgetter(0))] | ||||
|         return value_dict | ||||
|  | ||||
|     def to_mongo(self, value): | ||||
| @@ -238,7 +262,7 @@ class ComplexBaseField(BaseField): | ||||
|         if not hasattr(value, 'items'): | ||||
|             try: | ||||
|                 is_list = True | ||||
|                 value = dict([(k,v) for k,v in enumerate(value)]) | ||||
|                 value = dict([(k, v) for k, v in enumerate(value)]) | ||||
|             except TypeError:  # Not iterable return the value | ||||
|                 return value | ||||
|  | ||||
| @@ -246,13 +270,12 @@ class ComplexBaseField(BaseField): | ||||
|             value_dict = dict([(key, self.field.to_mongo(item)) for key, item in value.items()]) | ||||
|         else: | ||||
|             value_dict = {} | ||||
|             for k,v in value.items(): | ||||
|             for k, v in value.items(): | ||||
|                 if isinstance(v, Document): | ||||
|                     # We need the id from the saved object to create the DBRef | ||||
|                     if v.pk is None: | ||||
|                         raise ValidationError('You can only reference ' | ||||
|                                       'documents once they have been saved ' | ||||
|                                       'to the database ("%s")' % self.name) | ||||
|                         self.error('You can only reference documents once they' | ||||
|                                    ' have been saved to the database') | ||||
|  | ||||
|                     # If its a document that is not inheritable it won't have | ||||
|                     # _types / _cls data so make it a generic reference allows | ||||
| @@ -270,26 +293,33 @@ class ComplexBaseField(BaseField): | ||||
|                     value_dict[k] = self.to_mongo(v) | ||||
|  | ||||
|         if is_list:  # Convert back to a list | ||||
|             return [v for k,v in sorted(value_dict.items(), key=operator.itemgetter(0))] | ||||
|             return [v for k, v in sorted(value_dict.items(), key=operator.itemgetter(0))] | ||||
|         return value_dict | ||||
|  | ||||
|     def validate(self, value): | ||||
|         """If field provided ensure the value is valid. | ||||
|         """If field is provided ensure the value is valid. | ||||
|         """ | ||||
|         errors = {} | ||||
|         if self.field: | ||||
|             try: | ||||
|                 if hasattr(value, 'iteritems'): | ||||
|                     [self.field.validate(v) for k,v in value.iteritems()] | ||||
|                 else: | ||||
|                     [self.field.validate(v) for v in value] | ||||
|             except Exception, err: | ||||
|                 raise ValidationError('Invalid %s item (%s) ("%s")' % ( | ||||
|                         self.field.__class__.__name__, str(v), self.name)) | ||||
|  | ||||
|             if hasattr(value, 'iteritems'): | ||||
|                 sequence = value.iteritems() | ||||
|             else: | ||||
|                 sequence = enumerate(value) | ||||
|             for k, v in sequence: | ||||
|                 try: | ||||
|                     self.field.validate(v) | ||||
|                 except (ValidationError, AssertionError), error: | ||||
|                     if hasattr(error, 'errors'): | ||||
|                         errors[k] = error.errors | ||||
|                     else: | ||||
|                         errors[k] = error | ||||
|             if errors: | ||||
|                 field_class = self.field.__class__.__name__ | ||||
|                 self.error('Invalid %s item (%s)' % (field_class, value), | ||||
|                            errors=errors) | ||||
|         # Don't allow empty values if required | ||||
|         if self.required and not value: | ||||
|             raise ValidationError('Field "%s" is required and cannot be empty' % | ||||
|                                   self.name) | ||||
|             self.error('Field is required and cannot be empty') | ||||
|  | ||||
|     def prepare_query_value(self, op, value): | ||||
|         return self.to_mongo(value) | ||||
| @@ -344,6 +374,7 @@ class BaseDynamicField(BaseField): | ||||
|     def lookup_member(self, member_name): | ||||
|         return member_name | ||||
|  | ||||
|  | ||||
| class ObjectIdField(BaseField): | ||||
|     """An field wrapper around MongoDB's ObjectIds. | ||||
|     """ | ||||
| @@ -356,8 +387,8 @@ class ObjectIdField(BaseField): | ||||
|             try: | ||||
|                 return pymongo.objectid.ObjectId(unicode(value)) | ||||
|             except Exception, e: | ||||
|                 #e.message attribute has been deprecated since Python 2.6 | ||||
|                 raise ValidationError(unicode(e)) | ||||
|                 # e.message attribute has been deprecated since Python 2.6 | ||||
|                 self.error(unicode(e)) | ||||
|         return value | ||||
|  | ||||
|     def prepare_query_value(self, op, value): | ||||
| @@ -367,7 +398,7 @@ class ObjectIdField(BaseField): | ||||
|         try: | ||||
|             pymongo.objectid.ObjectId(unicode(value)) | ||||
|         except: | ||||
|             raise ValidationError('Invalid Object ID ("%s")' % self.name) | ||||
|             self.error('Invalid Object ID') | ||||
|  | ||||
|  | ||||
| class DocumentMetaclass(type): | ||||
| @@ -393,7 +424,7 @@ class DocumentMetaclass(type): | ||||
|                 superclasses[base._class_name] = base | ||||
|                 superclasses.update(base._superclasses) | ||||
|             else:  # Add any mixin fields | ||||
|                 attrs.update(dict([(k,v) for k,v in base.__dict__.items() | ||||
|                 attrs.update(dict([(k, v) for k, v in base.__dict__.items() | ||||
|                                     if issubclass(v.__class__, BaseField)])) | ||||
|  | ||||
|             if hasattr(base, '_meta') and not base._meta.get('abstract'): | ||||
| @@ -488,7 +519,7 @@ class TopLevelDocumentMetaclass(DocumentMetaclass): | ||||
|             ('meta' in attrs and attrs['meta'].get('abstract', False))): | ||||
|             # Make sure no base class was non-abstract | ||||
|             non_abstract_bases = [b for b in bases | ||||
|                 if hasattr(b,'_meta') and not b._meta.get('abstract', False)] | ||||
|                 if hasattr(b, '_meta') and not b._meta.get('abstract', False)] | ||||
|             if non_abstract_bases: | ||||
|                 raise ValueError("Abstract document cannot have non-abstract base") | ||||
|             return super_new(cls, name, bases, attrs) | ||||
| @@ -665,7 +696,7 @@ class BaseDocument(object): | ||||
|         signals.post_init.send(self.__class__, document=self) | ||||
|  | ||||
|     def __setattr__(self, name, value): | ||||
|         # Handle dynamic data only if an intialised dynamic document | ||||
|         # Handle dynamic data only if an initialised dynamic document | ||||
|         if self._dynamic and getattr(self, '_initialised', False): | ||||
|  | ||||
|             field = None | ||||
| @@ -708,7 +739,8 @@ class BaseDocument(object): | ||||
|             data[k] = self.__expand_dynamic_values(key, v) | ||||
|  | ||||
|         if is_list:  # Convert back to a list | ||||
|             value = [v for k, v in sorted(data.items(), key=operator.itemgetter(0))] | ||||
|             data_items = sorted(data.items(), key=operator.itemgetter(0)) | ||||
|             value = [v for k, v in data_items] | ||||
|         else: | ||||
|             value = data | ||||
|  | ||||
| @@ -729,15 +761,22 @@ class BaseDocument(object): | ||||
|                   for name, field in self._fields.items()] | ||||
|  | ||||
|         # Ensure that each field is matched to a valid value | ||||
|         errors = {} | ||||
|         for field, value in fields: | ||||
|             if value is not None: | ||||
|                 try: | ||||
|                     field._validate(value) | ||||
|                 except (ValueError, AttributeError, AssertionError), e: | ||||
|                     raise ValidationError('Invalid value for field named "%s" of type "%s": %s' | ||||
|                                           % (field.name, field.__class__.__name__, value)) | ||||
|                 except ValidationError, error: | ||||
|                     errors[field.name] = error.errors or error | ||||
|                 except (ValueError, AttributeError, AssertionError), error: | ||||
|                     errors[field.name] = error | ||||
|             elif field.required: | ||||
|                 raise ValidationError('Field "%s" is required' % field.name) | ||||
|                 errors[field.name] = ValidationError('Field is required', | ||||
|                                                      field_name=field.name) | ||||
|         if errors: | ||||
|             error = ValidationError('Errors encountered validating document') | ||||
|             error.errors = errors | ||||
|             raise error | ||||
|  | ||||
|     @apply | ||||
|     def pk(): | ||||
| @@ -745,8 +784,10 @@ class BaseDocument(object): | ||||
|         """ | ||||
|         def fget(self): | ||||
|             return getattr(self, self._meta['id_field']) | ||||
|  | ||||
|         def fset(self, value): | ||||
|             return setattr(self, self._meta['id_field'], value) | ||||
|  | ||||
|         return property(fget, fset) | ||||
|  | ||||
|     def to_mongo(self): | ||||
| @@ -821,7 +862,6 @@ class BaseDocument(object): | ||||
|                     """.strip() % class_name) | ||||
|             cls = subclasses[class_name] | ||||
|  | ||||
|         present_fields = data.keys() | ||||
|         for field_name, field in cls._fields.items(): | ||||
|             if field.db_field in data: | ||||
|                 value = data[field.db_field] | ||||
| @@ -972,8 +1012,7 @@ class BaseDocument(object): | ||||
|         return geo_indices | ||||
|  | ||||
|     def __getstate__(self): | ||||
|         self_dict = self.__dict__ | ||||
|         removals = ["get_%s_display" % k for k,v in self._fields.items() if v.choices] | ||||
|         removals = ["get_%s_display" % k for k, v in self._fields.items() if v.choices] | ||||
|         for k in removals: | ||||
|             if hasattr(self, k): | ||||
|                 delattr(self, k) | ||||
| @@ -1048,7 +1087,7 @@ class BaseDocument(object): | ||||
|     def __hash__(self): | ||||
|         if self.pk is None: | ||||
|             # For new object | ||||
|             return super(BaseDocument,self).__hash__() | ||||
|             return super(BaseDocument, self).__hash__() | ||||
|         else: | ||||
|             return hash(self.pk) | ||||
|  | ||||
|   | ||||
| @@ -44,17 +44,13 @@ class StringField(BaseField): | ||||
|         assert isinstance(value, (str, unicode)) | ||||
|  | ||||
|         if self.max_length is not None and len(value) > self.max_length: | ||||
|             raise ValidationError('String value is too long ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('String value is too long') | ||||
|  | ||||
|         if self.min_length is not None and len(value) < self.min_length: | ||||
|             raise ValidationError('String value is too short ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('String value is too short') | ||||
|  | ||||
|         if self.regex is not None and self.regex.match(value) is None: | ||||
|             message = 'String value did not match validation regex ("%s")' % \ | ||||
|                        self.name | ||||
|             raise ValidationError(message) | ||||
|             self.error('String value did not match validation regex') | ||||
|  | ||||
|     def lookup_member(self, member_name): | ||||
|         return None | ||||
| @@ -111,11 +107,9 @@ class URLField(StringField): | ||||
|             import urllib2 | ||||
|             try: | ||||
|                 request = urllib2.Request(value) | ||||
|                 response = urllib2.urlopen(request) | ||||
|                 urllib2.urlopen(request) | ||||
|             except Exception, e: | ||||
|                 message = 'This URL appears to be a broken link: %s ("%s")' % ( | ||||
|                           e, self.name) | ||||
|                 raise ValidationError(message) | ||||
|                 self.error('This URL appears to be a broken link: %s' % e) | ||||
|  | ||||
|  | ||||
| class EmailField(StringField): | ||||
| @@ -132,8 +126,7 @@ class EmailField(StringField): | ||||
|  | ||||
|     def validate(self, value): | ||||
|         if not EmailField.EMAIL_REGEX.match(value): | ||||
|             raise ValidationError('Invalid Mail-address: %s ("%s")' % (value, | ||||
|                                   self.name)) | ||||
|             self.error('Invalid Mail-address: %s' % value) | ||||
|  | ||||
|  | ||||
| class IntField(BaseField): | ||||
| @@ -151,16 +144,13 @@ class IntField(BaseField): | ||||
|         try: | ||||
|             value = int(value) | ||||
|         except: | ||||
|             raise ValidationError('%s could not be converted to int ("%s")' % ( | ||||
|                                   value, self.name)) | ||||
|             raise self.error('%s could not be converted to int' % value) | ||||
|  | ||||
|         if self.min_value is not None and value < self.min_value: | ||||
|             raise ValidationError('Integer value is too small ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Integer value is too small') | ||||
|  | ||||
|         if self.max_value is not None and value > self.max_value: | ||||
|             raise ValidationError('Integer value is too large ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Integer value is too large') | ||||
|  | ||||
|     def prepare_query_value(self, op, value): | ||||
|         return int(value) | ||||
| @@ -183,12 +173,10 @@ class FloatField(BaseField): | ||||
|         assert isinstance(value, float) | ||||
|  | ||||
|         if self.min_value is not None and value < self.min_value: | ||||
|             raise ValidationError('Float value is too small ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Float value is too small') | ||||
|  | ||||
|         if self.max_value is not None and value > self.max_value: | ||||
|             raise ValidationError('Float value is too large ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Float value is too large') | ||||
|  | ||||
|     def prepare_query_value(self, op, value): | ||||
|         return float(value) | ||||
| @@ -219,16 +207,13 @@ class DecimalField(BaseField): | ||||
|             try: | ||||
|                 value = decimal.Decimal(value) | ||||
|             except Exception, exc: | ||||
|                 raise ValidationError('Could not convert value to decimal: %s' | ||||
|                                       '("%s")' % (exc, self.name)) | ||||
|                 self.error('Could not convert value to decimal: %s' % exc) | ||||
|  | ||||
|         if self.min_value is not None and value < self.min_value: | ||||
|             raise ValidationError('Decimal value is too small ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Decimal value is too small') | ||||
|  | ||||
|         if self.max_value is not None and value > self.max_value: | ||||
|             raise ValidationError('Decimal value is too large ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Decimal value is too large') | ||||
|  | ||||
|  | ||||
| class BooleanField(BaseField): | ||||
| @@ -375,8 +360,8 @@ class ComplexDateTimeField(StringField): | ||||
|  | ||||
|     def validate(self, value): | ||||
|         if not isinstance(value, datetime.datetime): | ||||
|             raise ValidationError('Only datetime objects may used in a ' | ||||
|                                   'ComplexDateTimeField ("%s")' % self.name) | ||||
|             self.error('Only datetime objects may used in a ' | ||||
|                        'ComplexDateTimeField') | ||||
|  | ||||
|     def to_python(self, value): | ||||
|         return self._convert_from_string(value) | ||||
| @@ -396,9 +381,8 @@ class EmbeddedDocumentField(BaseField): | ||||
|     def __init__(self, document_type, **kwargs): | ||||
|         if not isinstance(document_type, basestring): | ||||
|             if not issubclass(document_type, EmbeddedDocument): | ||||
|                 raise ValidationError('Invalid embedded document class ' | ||||
|                                       'provided to an EmbeddedDocumentField ' | ||||
|                                       '("%s")' % self.name) | ||||
|                 self.error('Invalid embedded document class provided to an ' | ||||
|                            'EmbeddedDocumentField') | ||||
|         self.document_type_obj = document_type | ||||
|         super(EmbeddedDocumentField, self).__init__(**kwargs) | ||||
|  | ||||
| @@ -427,9 +411,8 @@ class EmbeddedDocumentField(BaseField): | ||||
|         """ | ||||
|         # Using isinstance also works for subclasses of self.document | ||||
|         if not isinstance(value, self.document_type): | ||||
|             raise ValidationError('Invalid embedded document instance ' | ||||
|                                   'provided to an EmbeddedDocumentField ' | ||||
|                                   '("%s")' % self.name) | ||||
|             self.error('Invalid embedded document instance provided to an ' | ||||
|                        'EmbeddedDocumentField') | ||||
|         self.document_type.validate(value) | ||||
|  | ||||
|     def lookup_member(self, member_name): | ||||
| @@ -458,9 +441,8 @@ class GenericEmbeddedDocumentField(BaseField): | ||||
|  | ||||
|     def validate(self, value): | ||||
|         if not isinstance(value, EmbeddedDocument): | ||||
|             raise ValidationError('Invalid embedded document instance ' | ||||
|                                   'provided to an GenericEmbeddedDocumentField ' | ||||
|                                   '("%s")' % self.name) | ||||
|             self.error('Invalid embedded document instance provided to an ' | ||||
|                        'GenericEmbeddedDocumentField') | ||||
|  | ||||
|         value.validate() | ||||
|  | ||||
| @@ -495,8 +477,7 @@ class ListField(ComplexBaseField): | ||||
|         """ | ||||
|         if (not isinstance(value, (list, tuple)) or | ||||
|             isinstance(value, basestring)): | ||||
|             raise ValidationError('Only lists and tuples may be used in a ' | ||||
|                                   'list field ("%s")' % self.name) | ||||
|             self.error('Only lists and tuples may be used in a list field') | ||||
|         super(ListField, self).validate(value) | ||||
|  | ||||
|     def prepare_query_value(self, op, value): | ||||
| @@ -552,13 +533,11 @@ class DictField(ComplexBaseField): | ||||
|         """Make sure that a list of valid fields is being used. | ||||
|         """ | ||||
|         if not isinstance(value, dict): | ||||
|             raise ValidationError('Only dictionaries may be used in a ' | ||||
|                                   'DictField ("%s")' % self.name) | ||||
|             self.error('Only dictionaries may be used in a DictField') | ||||
|  | ||||
|         if any(('.' in k or '$' in k) for k in value): | ||||
|             raise ValidationError('Invalid dictionary key name - keys may not ' | ||||
|                                   'contain "." or "$" characters ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Invalid dictionary key name - keys may not contain "."' | ||||
|                        ' or "$" characters') | ||||
|         super(DictField, self).validate(value) | ||||
|  | ||||
|     def lookup_member(self, member_name): | ||||
| @@ -585,12 +564,11 @@ class MapField(DictField): | ||||
|  | ||||
|     def __init__(self, field=None, *args, **kwargs): | ||||
|         if not isinstance(field, BaseField): | ||||
|             raise ValidationError('Argument to MapField constructor must be ' | ||||
|                                   'a valid field') | ||||
|             self.error('Argument to MapField constructor must be a valid ' | ||||
|                        'field') | ||||
|         super(MapField, self).__init__(field=field, *args, **kwargs) | ||||
|  | ||||
|  | ||||
|  | ||||
| class ReferenceField(BaseField): | ||||
|     """A reference to a document that will be automatically dereferenced on | ||||
|     access (lazily). | ||||
| @@ -616,8 +594,8 @@ class ReferenceField(BaseField): | ||||
|         """ | ||||
|         if not isinstance(document_type, basestring): | ||||
|             if not issubclass(document_type, (Document, basestring)): | ||||
|                 raise ValidationError('Argument to ReferenceField constructor ' | ||||
|                                       'must be a document class or a string') | ||||
|                 self.error('Argument to ReferenceField constructor must be a ' | ||||
|                            'document class or a string') | ||||
|         self.document_type_obj = document_type | ||||
|         self.reverse_delete_rule = reverse_delete_rule | ||||
|         super(ReferenceField, self).__init__(**kwargs) | ||||
| @@ -656,8 +634,8 @@ class ReferenceField(BaseField): | ||||
|             # We need the id from the saved object to create the DBRef | ||||
|             id_ = document.id | ||||
|             if id_ is None: | ||||
|                 raise ValidationError('You can only reference documents once ' | ||||
|                                       'they have been saved to the database') | ||||
|                 self.error('You can only reference documents once they have' | ||||
|                            ' been saved to the database') | ||||
|         else: | ||||
|             id_ = document | ||||
|  | ||||
| @@ -672,10 +650,8 @@ class ReferenceField(BaseField): | ||||
|         assert isinstance(value, (self.document_type, pymongo.dbref.DBRef)) | ||||
|  | ||||
|         if isinstance(value, Document) and value.id is None: | ||||
|             raise ValidationError('You can only reference documents once ' | ||||
|                                   'they have been saved to the database ' | ||||
|                                   '("%s")' % self.name) | ||||
|  | ||||
|             raise self.error('You can only reference documents once they have' | ||||
|                              ' been saved to the database') | ||||
|  | ||||
|     def lookup_member(self, member_name): | ||||
|         return self.document_type._fields.get(member_name) | ||||
| @@ -703,14 +679,12 @@ class GenericReferenceField(BaseField): | ||||
|  | ||||
|     def validate(self, value): | ||||
|         if not isinstance(value, (Document, pymongo.dbref.DBRef)): | ||||
|             raise ValidationError('GenericReferences can only contain ' | ||||
|                                   'documents ("%s")' % self.name) | ||||
|             raise self.error('GenericReferences can only contain documents') | ||||
|  | ||||
|         # We need the id from the saved object to create the DBRef | ||||
|         if isinstance(value, Document) and value.id is None: | ||||
|             raise ValidationError('You can only reference documents once ' | ||||
|                                   'they have been saved to the database ' | ||||
|                                   '("%s")' % self.name) | ||||
|             self.error('You can only reference documents once they have been' | ||||
|                        ' saved to the database') | ||||
|  | ||||
|     def dereference(self, value): | ||||
|         doc_cls = get_document(value['_cls']) | ||||
| @@ -731,9 +705,8 @@ class GenericReferenceField(BaseField): | ||||
|             # We need the id from the saved object to create the DBRef | ||||
|             id_ = document.id | ||||
|             if id_ is None: | ||||
|                 raise ValidationError('You can only reference documents once ' | ||||
|                                       'they have been saved to the database ' | ||||
|                                       '("%s")' % self.name) | ||||
|                 self.error('You can only reference documents once they have' | ||||
|                            ' been saved to the database') | ||||
|         else: | ||||
|             id_ = document | ||||
|  | ||||
| @@ -765,8 +738,7 @@ class BinaryField(BaseField): | ||||
|         assert isinstance(value, str) | ||||
|  | ||||
|         if self.max_bytes is not None and len(value) > self.max_bytes: | ||||
|             raise ValidationError('Binary value is too long ("%s")' % | ||||
|                                   self.name) | ||||
|             self.error('Binary value is too long') | ||||
|  | ||||
|  | ||||
| class GridFSError(Exception): | ||||
| @@ -940,16 +912,14 @@ class GeoPointField(BaseField): | ||||
|         """Make sure that a geo-value is of type (x, y) | ||||
|         """ | ||||
|         if not isinstance(value, (list, tuple)): | ||||
|             raise ValidationError('GeoPointField can only accept tuples or ' | ||||
|                                   'lists of (x, y) ("%s")' % self.name) | ||||
|             self.error('GeoPointField can only accept tuples or lists ' | ||||
|                        'of (x, y)') | ||||
|  | ||||
|         if not len(value) == 2: | ||||
|             raise ValidationError('Value must be a two-dimensional point ' | ||||
|                                   '("%s")' % self.name) | ||||
|             raise self.error('Value must be a two-dimensional point') | ||||
|         if (not isinstance(value[0], (float, int)) and | ||||
|             not isinstance(value[1], (float, int))): | ||||
|             raise ValidationError('Both values in point must be float or int ' | ||||
|                                   '("%s")' % self.name) | ||||
|             self.error('Both values in point must be float or int') | ||||
|  | ||||
|  | ||||
| class SequenceField(IntField): | ||||
| @@ -1036,4 +1006,4 @@ class UUIDField(BaseField): | ||||
|             try: | ||||
|                 value = uuid.UUID(value) | ||||
|             except Exception, exc: | ||||
|                 raise ValidationError('Could not convert to UUID: %s' % exc) | ||||
|                 self.error('Could not convert to UUID: %s' % exc) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user