Merge pull request #218 from Mimino666/django-item-validation

Django item validation
This commit is contained in:
Pablo Hoffman 2013-01-04 10:35:20 -08:00
commit acb7bad1ff
2 changed files with 81 additions and 6 deletions

View File

@ -1,3 +1,5 @@
from django.core.exceptions import ValidationError
from scrapy.item import Field, Item, ItemMeta
@ -24,10 +26,49 @@ class DjangoItem(Item):
django_model = None
def __init__(self, *args, **kwargs):
super(DjangoItem, self).__init__(*args, **kwargs)
self._instance = None
self._errors = None
def save(self, commit=True):
modelargs = dict((k, self.get(k)) for k in self._values
if k in self._model_fields)
model = self.django_model(**modelargs)
if commit:
model.save()
return model
self.instance.save()
return self.instance
def is_valid(self, exclude=None):
self._get_errors(exclude)
return not bool(self._errors)
def _get_errors(self, exclude=None):
if self._errors is not None:
return self._errors
self._errors = {}
if exclude is None:
exclude = []
try:
self.instance.clean_fields(exclude=exclude)
except ValidationError, e:
self._errors = e.update_error_dict(self._errors)
try:
self.instance.clean()
except ValidationError, e:
self._errors = e.update_error_dict(self._errors)
# uniqueness is not checked, because it is faster to check it when
# saving object to database. Just beware, that failed save()
# raises IntegrityError instead of ValidationError.
return self._errors
errors = property(_get_errors)
@property
def instance(self):
if self._instance is None:
modelargs = dict((k, self.get(k)) for k in self._values
if k in self._model_fields)
self._instance = self.django_model(**modelargs)
return self._instance

View File

@ -34,7 +34,7 @@ class IdentifiedPersonItem(DjangoItem):
class DjangoItemTest(unittest.TestCase):
def setUp(self):
if not django:
raise unittest.SkipTest("Django is not available")
@ -74,9 +74,43 @@ class DjangoItemTest(unittest.TestCase):
i = OverrideFieldPersonItem()
i['name'] = 'John'
# it is not obvious that "age" should be saved also, since it was
# redefined in child class
i['age'] = '22'
person = i.save(commit=False)
self.assertEqual(person.name, 'John')
self.assertEqual(person.age, '22')
def test_validation(self):
long_name = 'z' * 300
i = BasePersonItem(name=long_name)
self.assertFalse(i.is_valid())
self.assertDictEqual(
{
'age': [u'This field cannot be null.'],
'name': [u'Ensure this value has at most 255 characters (it has 300).']
},
i.errors)
i = BasePersonItem(name='John')
self.assertTrue(i.is_valid(exclude=['age']))
self.assertDictEqual({}, i.errors)
# once the item is validated, it does not validate again
i['name'] = long_name
self.assertTrue(i.is_valid())
def test_override_validation(self):
i = OverrideFieldPersonItem()
i['name'] = 'John'
self.assertFalse(i.is_valid())
i = i = OverrideFieldPersonItem()
i['name'] = 'John'
i['age'] = '22'
self.assertTrue(i.is_valid())
def test_default_field_values(self):
i = BasePersonItem()