Skip to content

Commit 704c9a6

Browse files
committedNov 15, 2012
Initial import
1 parent 020a17b commit 704c9a6

13 files changed

+208
-0
lines changed
 

‎README.rst

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
====================
2+
django-import-export
3+
====================

‎import_export/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
VERSION = (0, 0, '1dev')
2+
__version__ = '.'.join(map(str, VERSION))

‎import_export/core.py

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from collections import OrderedDict
2+
3+
import tablib
4+
5+
from django.utils.translation import ugettext_lazy as _
6+
7+
8+
class RowResult(object):
9+
10+
def __init__(self):
11+
self.errors = []
12+
self.orig_fields = []
13+
self.fields = []
14+
15+
16+
class Result(list):
17+
18+
def __init__(self, *args, **kwargs):
19+
super(Result, self).__init__(*args, **kwargs)
20+
self.base_errors = []
21+
22+
def row_errors(self):
23+
return [(i, row.errors) for i, row in enumerate(self) if row.errors]
24+
25+
def has_errors(self):
26+
return self.base_errors or self.row_errors()
27+
28+
29+
class Importer(object):
30+
model = None
31+
format = None
32+
import_code = "ID"
33+
raise_errors = True
34+
dry_run = True
35+
mapping = None
36+
37+
def __init__(self, f, **kwargs):
38+
self.f = f
39+
for key, value in kwargs.iteritems():
40+
setattr(self, key, value)
41+
42+
def get_mapping(self):
43+
if self.mapping:
44+
return self.mapping
45+
mapping = [(f.verbose_name, f.name) for f in self.model._meta.fields]
46+
return OrderedDict(mapping)
47+
48+
def load_dataset(self):
49+
text = unicode(self.f.read(), 'cp1250').encode('utf-8')
50+
if not self.format:
51+
self.data = tablib.import_set(text)
52+
else:
53+
self.data = tablib.Dataset()
54+
self.format.import_set(self.data, text)
55+
56+
def get_instance(self, row):
57+
return self.model.objects.get(**{
58+
self.get_mapping()[self.import_code]: row[self.import_code]
59+
})
60+
61+
def init_instance(self, row):
62+
return self.model()
63+
64+
def get_or_init_instance(self, row):
65+
try:
66+
instance = self.get_instance(row)
67+
except self.model.DoesNotExist:
68+
instance = self.init_instance(row)
69+
return instance
70+
71+
def set_instance_attr(self, instance, row, field):
72+
setattr(instance, self.get_mapping()[field], row[field])
73+
74+
def save_instance(self, instance):
75+
if not self.dry_run:
76+
instance.save()
77+
78+
def get_representation(self, instance):
79+
return [unicode(getattr(instance, f))
80+
for f in self.get_mapping().values()]
81+
82+
def run(self):
83+
result = Result()
84+
try:
85+
self.load_dataset()
86+
except Exception, e:
87+
result.base_errors.append(_('Loading error') +
88+
u': %s' % unicode(e))
89+
if self.raise_errors:
90+
raise
91+
return result
92+
93+
for row in self.data.dict:
94+
try:
95+
row_result = RowResult()
96+
instance = self.get_or_init_instance(row)
97+
row_result.orig_fields = self.get_representation(instance)
98+
for field in self.get_mapping().keys():
99+
self.set_instance_attr(instance, row, field)
100+
self.save_instance(instance)
101+
row_result.fields = self.get_representation(instance)
102+
except Exception, e:
103+
row_result.errors.append(unicode(e))
104+
if self.raise_errors:
105+
raise
106+
result.append(row_result)
107+
return result

‎import_export/models.py

Whitespace-only changes.

‎requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Django>=1.4
2+
tablib

‎runtests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PYTHONPATH=".:tests:$PYTHONPATH" django-admin.py test core --settings=settings

‎setup.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from setuptools import setup, find_packages
2+
import os
3+
4+
5+
VERSION = __import__("send_instance").__version__
6+
7+
CLASSIFIERS = [
8+
'Framework :: Django',
9+
'Intended Audience :: Developers',
10+
'License :: OSI Approved :: BSD License',
11+
'Operating System :: OS Independent',
12+
'Topic :: Software Development',
13+
]
14+
15+
install_requires = [
16+
'tablib',
17+
'Django>=1.4.2',
18+
]
19+
20+
setup(
21+
name="django-import-export",
22+
description="django-import-export",
23+
long_description=open(os.path.join(os.path.dirname(__file__),
24+
'README.rst')).read(),
25+
version=VERSION,
26+
author="Informatika Mihelac",
27+
author_email="bmihelac@mihelac.org",
28+
url="https://github.com/bmihelac/django-import-export",
29+
packages=find_packages(exclude=["tests"]),
30+
)

‎tests/__init__.py

Whitespace-only changes.

‎tests/core/__init__.py

Whitespace-only changes.

‎tests/core/exports/books.csv

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ID,Book name,Author email
2+
1,Some book,test@example.com

‎tests/core/models.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.db import models
2+
3+
4+
class Book(models.Model):
5+
name = models.CharField('Book name', max_length=100)
6+
author_email = models.EmailField('Author email', max_length=75, blank=True)
7+
8+
def __unicode__(self):
9+
return self.name

‎tests/core/tests.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import os.path
2+
3+
from django.test import TestCase
4+
5+
from import_export.core import Importer
6+
7+
from .models import Book
8+
9+
10+
class BookImporter(Importer):
11+
12+
model = Book
13+
14+
15+
class ImporterTest(TestCase):
16+
17+
def setUp(self):
18+
self.filename = os.path.join(os.path.dirname(__file__), 'exports',
19+
'books.csv')
20+
21+
def test_import_create(self):
22+
result = BookImporter(open(self.filename), dry_run=False).run()
23+
self.assertFalse(result.has_errors())
24+
self.assertEqual(Book.objects.count(), 1)
25+
26+
def test_import_update(self):
27+
Book.objects.create(id=1, name="Other book")
28+
result = BookImporter(open(self.filename), dry_run=False).run()
29+
self.assertFalse(result.has_errors())
30+
self.assertEqual(Book.objects.count(), 1)
31+
self.assertEqual(Book.objects.all()[0].name, "Some book")
32+
self.assertNotEqual(result[0].orig_fields[1], result[0].fields[1])

‎tests/settings.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
DATABASES = {
2+
'default': {
3+
'ENGINE': 'django.db.backends.sqlite3',
4+
'NAME': 'haystack_tests.db',
5+
}
6+
}
7+
8+
INSTALLED_APPS = [
9+
'django.contrib.admin',
10+
'django.contrib.auth',
11+
'django.contrib.contenttypes',
12+
'django.contrib.sessions',
13+
'django.contrib.sites',
14+
15+
'import_export',
16+
17+
'core',
18+
]
19+
20+
SITE_ID = 1

0 commit comments

Comments
 (0)
Please sign in to comment.