From decbdc534644384c18a603dc35650b044d0b5a0a Mon Sep 17 00:00:00 2001 From: Ismael Carnales Date: Mon, 24 Aug 2009 17:16:18 -0300 Subject: [PATCH] added DjangoItem item class --- scrapy/contrib_exp/djangoitem.py | 37 ++++++++++++++++ scrapy/item.py | 9 ++-- scrapy/tests/test_djangoitem/__init__.py | 56 ++++++++++++++++++++++++ scrapy/tests/test_djangoitem/models.py | 10 +++++ scrapy/tests/test_djangoitem/settings.py | 2 + 5 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 scrapy/contrib_exp/djangoitem.py create mode 100644 scrapy/tests/test_djangoitem/__init__.py create mode 100644 scrapy/tests/test_djangoitem/models.py create mode 100644 scrapy/tests/test_djangoitem/settings.py diff --git a/scrapy/contrib_exp/djangoitem.py b/scrapy/contrib_exp/djangoitem.py new file mode 100644 index 000000000..22a23af14 --- /dev/null +++ b/scrapy/contrib_exp/djangoitem.py @@ -0,0 +1,37 @@ +from scrapy.item import DictItem, Field + + +class DjangoItemMeta(type): + + def __new__(mcs, class_name, bases, attrs): + cls = super(DjangoItemMeta, mcs).__new__(mcs, class_name, bases, attrs) + cls.fields = cls.fields.copy() + + if cls.django_model: + cls._model_fields = [] + cls._model_meta = cls.django_model._meta + for model_field in cls._model_meta.fields: + # XXX: for now we're treating each PK as autogenerated field + if model_field != cls._model_meta.pk: + cls.fields[model_field.name] = Field() + cls._model_fields.append(model_field.name) + # add declared fields + for n, v in attrs.iteritems(): + if isinstance(v, Field): + cls.fields[n] = v + return cls + + +class DjangoItem(DictItem): + + __metaclass__ = DjangoItemMeta + + django_model = None + + def save(self, commit=True): + modelargs = dict((f, self.get(f, None)) for f in self._model_fields) + model = self.django_model(**modelargs) + if commit: + model.save() + return model + diff --git a/scrapy/item.py b/scrapy/item.py index 20f52d72d..f51ac35db 100644 --- a/scrapy/item.py +++ b/scrapy/item.py @@ -34,9 +34,7 @@ class _ItemMeta(type): return cls -class Item(DictMixin, BaseItem): - - __metaclass__ = _ItemMeta +class DictItem(DictMixin, BaseItem): fields = {} @@ -81,6 +79,11 @@ class Item(DictMixin, BaseItem): return "%s(%s)" % (self.__class__.__name__, values) +class Item(DictItem): + + __metaclass__ = _ItemMeta + + class ScrapedItem(BaseItem): def __init__(self, data=None): diff --git a/scrapy/tests/test_djangoitem/__init__.py b/scrapy/tests/test_djangoitem/__init__.py new file mode 100644 index 000000000..7a0a3ca8f --- /dev/null +++ b/scrapy/tests/test_djangoitem/__init__.py @@ -0,0 +1,56 @@ +import os +from twisted.trial import unittest + +from scrapy.contrib_exp.djangoitem import DjangoItem, Field + +os.environ['DJANGO_SETTINGS_MODULE'] = 'scrapy.tests.test_djangoitem.settings' + +try: + from models import Person + django = True +except ImportError: + django = False + + +class BasePersonItem(DjangoItem): + django_model = Person + + +class NewFieldPersonItem(BasePersonItem): + other = Field() + + +class OverrideFieldPersonItem(BasePersonItem): + age = Field(default=1) + + +class DjangoItemTest(TestCase): + + def setUp( + if not django: + raise unittest.SkipTest("Django is not available") + + def test_base(self): + i = BasePersonItem() + self.assertEqual(i.fields.keys(), ['age', 'name']) + + def test_new_fields(self): + i = NewFieldPersonItem() + self.assertEqual(i.fields.keys(), ['age', 'other', 'name']) + + def test_override_field(self): + i = OverrideFieldPersonItem() + self.assertEqual(i.fields.keys(), ['age', 'name']) + self.assertEqual(i.fields['age'], {'default': 1}) + + def test_save(self): + i = BasePersonItem() + self.assertEqual(i.fields.keys(), ['age', 'name']) + + i['name'] = 'John' + i['age'] = '22' + person = i.save(commit=False) + + self.assertEqual(person.name, 'John') + self.assertEqual(person.age, '22') + diff --git a/scrapy/tests/test_djangoitem/models.py b/scrapy/tests/test_djangoitem/models.py new file mode 100644 index 000000000..57a8d648d --- /dev/null +++ b/scrapy/tests/test_djangoitem/models.py @@ -0,0 +1,10 @@ +from django.db import models + + +class Person(models.Model): + name = models.CharField(max_length=255) + age = models.IntegerField() + + class Meta: + app_label = 'test_djangoitem' + diff --git a/scrapy/tests/test_djangoitem/settings.py b/scrapy/tests/test_djangoitem/settings.py new file mode 100644 index 000000000..6ece9ee7a --- /dev/null +++ b/scrapy/tests/test_djangoitem/settings.py @@ -0,0 +1,2 @@ +DATABASE_ENGINE = 'sqlite3' +DATABASE_NAME = ':memory:'