Merge pull request #848 from seglberg/choice-subclasses
Field Choices Now Accept Subclasses of Documents
This commit is contained in:
commit
65f205bca8
2
AUTHORS
2
AUTHORS
@ -215,4 +215,4 @@ that much better:
|
|||||||
* André Ericson https://github.com/aericson)
|
* André Ericson https://github.com/aericson)
|
||||||
* Mikhail Moshnogorsky (https://github.com/mikhailmoshnogorsky)
|
* Mikhail Moshnogorsky (https://github.com/mikhailmoshnogorsky)
|
||||||
* Diego Berrocal (https://github.com/cestdiego)
|
* Diego Berrocal (https://github.com/cestdiego)
|
||||||
* Matthew Ellison (https://github.com/mmelliso)
|
* Matthew Ellison (https://github.com/seglberg)
|
||||||
|
@ -5,6 +5,7 @@ Changelog
|
|||||||
|
|
||||||
Changes in 0.9.X - DEV
|
Changes in 0.9.X - DEV
|
||||||
======================
|
======================
|
||||||
|
- Field Choices Now Accept Subclasses of Documents
|
||||||
- Ensure Indexes before Each Save #812
|
- Ensure Indexes before Each Save #812
|
||||||
- Generate Unique Indices for Lists of EmbeddedDocuments #358
|
- Generate Unique Indices for Lists of EmbeddedDocuments #358
|
||||||
- Sparse fields #515
|
- Sparse fields #515
|
||||||
|
@ -158,21 +158,23 @@ class BaseField(object):
|
|||||||
def _validate(self, value, **kwargs):
|
def _validate(self, value, **kwargs):
|
||||||
Document = _import_class('Document')
|
Document = _import_class('Document')
|
||||||
EmbeddedDocument = _import_class('EmbeddedDocument')
|
EmbeddedDocument = _import_class('EmbeddedDocument')
|
||||||
# check choices
|
|
||||||
|
# Check the Choices Constraint
|
||||||
if self.choices:
|
if self.choices:
|
||||||
is_cls = isinstance(value, (Document, EmbeddedDocument))
|
|
||||||
value_to_check = value.__class__ if is_cls else value
|
choice_list = self.choices
|
||||||
err_msg = 'an instance' if is_cls else 'one'
|
|
||||||
if isinstance(self.choices[0], (list, tuple)):
|
if isinstance(self.choices[0], (list, tuple)):
|
||||||
option_keys = [k for k, v in self.choices]
|
choice_list = [k for k, v in self.choices]
|
||||||
if value_to_check not in option_keys:
|
|
||||||
msg = ('Value must be %s of %s' %
|
# Choices which are other types of Documents
|
||||||
(err_msg, unicode(option_keys)))
|
if isinstance(value, (Document, EmbeddedDocument)):
|
||||||
self.error(msg)
|
if not any(isinstance(value, c) for c in choice_list):
|
||||||
elif value_to_check not in self.choices:
|
self.error(
|
||||||
msg = ('Value must be %s of %s' %
|
'Value must be instance of %s' % unicode(choice_list)
|
||||||
(err_msg, unicode(self.choices)))
|
)
|
||||||
self.error(msg)
|
# Choices which are types other than Documents
|
||||||
|
elif value not in choice_list:
|
||||||
|
self.error('Value must be one of %s' % unicode(choice_list))
|
||||||
|
|
||||||
# check validation argument
|
# check validation argument
|
||||||
if self.validation is not None:
|
if self.validation is not None:
|
||||||
|
@ -2446,6 +2446,79 @@ class FieldTest(unittest.TestCase):
|
|||||||
|
|
||||||
Shirt.drop_collection()
|
Shirt.drop_collection()
|
||||||
|
|
||||||
|
def test_choices_validation_documents(self):
|
||||||
|
"""
|
||||||
|
Ensure fields with document choices validate given a valid choice.
|
||||||
|
"""
|
||||||
|
class UserComments(EmbeddedDocument):
|
||||||
|
author = StringField()
|
||||||
|
message = StringField()
|
||||||
|
|
||||||
|
class BlogPost(Document):
|
||||||
|
comments = ListField(
|
||||||
|
GenericEmbeddedDocumentField(choices=(UserComments,))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure Validation Passes
|
||||||
|
BlogPost(comments=[
|
||||||
|
UserComments(author='user2', message='message2'),
|
||||||
|
]).save()
|
||||||
|
|
||||||
|
def test_choices_validation_documents_invalid(self):
|
||||||
|
"""
|
||||||
|
Ensure fields with document choices validate given an invalid choice.
|
||||||
|
This should throw a ValidationError exception.
|
||||||
|
"""
|
||||||
|
class UserComments(EmbeddedDocument):
|
||||||
|
author = StringField()
|
||||||
|
message = StringField()
|
||||||
|
|
||||||
|
class ModeratorComments(EmbeddedDocument):
|
||||||
|
author = StringField()
|
||||||
|
message = StringField()
|
||||||
|
|
||||||
|
class BlogPost(Document):
|
||||||
|
comments = ListField(
|
||||||
|
GenericEmbeddedDocumentField(choices=(UserComments,))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Single Entry Failure
|
||||||
|
post = BlogPost(comments=[
|
||||||
|
ModeratorComments(author='mod1', message='message1'),
|
||||||
|
])
|
||||||
|
self.assertRaises(ValidationError, post.save)
|
||||||
|
|
||||||
|
# Mixed Entry Failure
|
||||||
|
post = BlogPost(comments=[
|
||||||
|
ModeratorComments(author='mod1', message='message1'),
|
||||||
|
UserComments(author='user2', message='message2'),
|
||||||
|
])
|
||||||
|
self.assertRaises(ValidationError, post.save)
|
||||||
|
|
||||||
|
def test_choices_validation_documents_inheritance(self):
|
||||||
|
"""
|
||||||
|
Ensure fields with document choices validate given subclass of choice.
|
||||||
|
"""
|
||||||
|
class Comments(EmbeddedDocument):
|
||||||
|
meta = {
|
||||||
|
'abstract': True
|
||||||
|
}
|
||||||
|
author = StringField()
|
||||||
|
message = StringField()
|
||||||
|
|
||||||
|
class UserComments(Comments):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BlogPost(Document):
|
||||||
|
comments = ListField(
|
||||||
|
GenericEmbeddedDocumentField(choices=(Comments,))
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save Valid EmbeddedDocument Type
|
||||||
|
BlogPost(comments=[
|
||||||
|
UserComments(author='user2', message='message2'),
|
||||||
|
]).save()
|
||||||
|
|
||||||
def test_choices_get_field_display(self):
|
def test_choices_get_field_display(self):
|
||||||
"""Test dynamic helper for returning the display value of a choices
|
"""Test dynamic helper for returning the display value of a choices
|
||||||
field.
|
field.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user