mirror of https://github.com/scrapy/scrapy.git
Merge pull request #218 from Mimino666/django-item-validation
Django item validation
This commit is contained in:
commit
acb7bad1ff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue