summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@proxience.com>2015-05-05 13:03:09 +0200
committerÉtienne Loks <etienne.loks@proxience.com>2015-05-05 13:05:06 +0200
commit3c34bd06079b29d7af91ec15ad912e1faf60ecbb (patch)
tree333db30d0b6bbb112d77c32ca1b878c8f70ee69a
parentbdc9cdab0d5e314b5d1a33a2d87fca22138d649d (diff)
downloadIshtar-3c34bd06079b29d7af91ec15ad912e1faf60ecbb.tar.bz2
Ishtar-3c34bd06079b29d7af91ec15ad912e1faf60ecbb.zip
Imports: manage importation interface, error file
-rw-r--r--Makefile.example18
-rw-r--r--example_project/urls.py6
-rw-r--r--ishtar_common/data_importer.py7
-rw-r--r--ishtar_common/forms_common.py16
-rw-r--r--ishtar_common/migrations/0028_auto__chg_field_targetkey_key__chg_field_targetkey_value.py319
-rw-r--r--ishtar_common/models.py73
-rw-r--r--ishtar_common/templates/ishtar/import_list.html8
-rw-r--r--ishtar_common/views.py8
8 files changed, 433 insertions, 22 deletions
diff --git a/Makefile.example b/Makefile.example
index 7d37d6bc3..82f2a42e3 100644
--- a/Makefile.example
+++ b/Makefile.example
@@ -16,6 +16,8 @@ clean:
-find . -name '*.pyc' -exec rm {} \;
-find . -name '.*.swp' -exec rm {} \;
+update: clean syncdb compilemessages collectstatic
+
test: clean
cd $(project); $(PYTHON) manage.py test $(apps)
@@ -78,3 +80,19 @@ compilemessages:
cd $(CURDIR)/$$DIR; \
$(PYTHON) ../$(project)/manage.py compilemessages; \
done
+
+collectstatic:
+ cd $(project);$(PYTHON) manage.py collectstatic --noinput
+
+schemamigrations:
+ cd $(project);\
+ for APP in $(apps); do \
+ echo "* schemamigration for "$$APP; \
+ $(PYTHON) manage.py schemamigration --auto $$APP; \
+ done
+
+generate_doc:
+ cd $(project);\
+ $(PYTHON) manage.py graph_models --pydot -I "ImporterType,ImporterDefault,ImporterDefaultValues,ImporterColumn,Regexp,ImportTarget,FormaterType,Import" ishtar_common > /tmp/ishtar.dot
+ dot -Tpng /tmp/ishtar.dot -o docs/source/_static/db-imports.png
+ rm /tmp/ishtar.dot
diff --git a/example_project/urls.py b/example_project/urls.py
index e6ea1f37e..0c3b2a07f 100644
--- a/example_project/urls.py
+++ b/example_project/urls.py
@@ -30,3 +30,9 @@ urlpatterns += patterns('ishtar_common.views',
urlpatterns += patterns('',
(r'^admin/', include(admin.site.urls)),
)
+
+if settings.DEBUG:
+ # static files (images, css, javascript, etc.)
+ urlpatterns += patterns('',
+ (r'^media/(?P<path>.*)$', 'django.views.static.serve', {
+ 'document_root': settings.MEDIA_ROOT}))
diff --git a/ishtar_common/data_importer.py b/ishtar_common/data_importer.py
index cef98789e..24c8e166d 100644
--- a/ishtar_common/data_importer.py
+++ b/ishtar_common/data_importer.py
@@ -277,7 +277,7 @@ class StrChoiceFormater(Formater):
if output == 'db' and self.db_target:
from ishtar_common.models import TargetKey
for missing in self.missings:
- q = {'target':self.db_target, 'value':missing}
+ q = {'target':self.db_target, 'key':missing}
if TargetKey.objects.filter(**q).count():
continue
with transaction.commit_on_success():
@@ -409,7 +409,7 @@ class StrToBoolean(Formater):
from ishtar_common.models import TargetKey
for missing in self.missings:
try:
- q = {'target':self.db_target, 'value':missing}
+ q = {'target':self.db_target, 'key':missing}
models.TargetKey.objects.create(**q)
except IntegrityError:
pass
@@ -853,7 +853,8 @@ class Importer(object):
def get_csv_errors(self):
if not self.errors:
return ""
- csv_errors = ["line,col,error"]
+ csv_errors = ['"%s","%s","%s"' % (unicode(_("line")),
+ unicode(_("col")), unicode(_("error")))]
for line, col, error in self.errors:
csv_errors.append(u'"%s","%s","%s"' % (line and unicode(line) or '-',
col and unicode(col) or '-',
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index 677656af6..d8740b68c 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -101,10 +101,10 @@ class NewImportForm(forms.ModelForm):
class TargetKeyForm(forms.ModelForm):
class Meta:
model = models.TargetKey
- fields = ('target', 'value', 'key')
+ fields = ('target', 'key', 'value')
widgets = {
- 'value': forms.TextInput(attrs={'readonly':'readonly'}),
- 'key': forms.Select(),
+ 'key': forms.TextInput(attrs={'readonly':'readonly'}),
+ 'value': forms.Select(),
}
def __init__(self, *args, **kwargs):
@@ -112,8 +112,8 @@ class TargetKeyForm(forms.ModelForm):
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['target'].widget.attrs['readonly'] = True
- self.fields['value'].widget.attrs['readonly'] = True
- self.fields['key'].widget.choices = list(instance.target.get_choices())
+ self.fields['key'].widget.attrs['readonly'] = True
+ self.fields['value'].widget.choices = list(instance.target.get_choices())
def clean_target(self):
instance = getattr(self, 'instance', None)
@@ -122,12 +122,12 @@ class TargetKeyForm(forms.ModelForm):
else:
return self.cleaned_data['target']
- def clean_value(self):
+ def clean_key(self):
instance = getattr(self, 'instance', None)
if instance and instance.pk:
- return instance.value
+ return instance.key
else:
- return self.cleaned_data['value']
+ return self.cleaned_data['key']
def save(self, commit=True):
super(TargetKeyForm, self).save(commit)
diff --git a/ishtar_common/migrations/0028_auto__chg_field_targetkey_key__chg_field_targetkey_value.py b/ishtar_common/migrations/0028_auto__chg_field_targetkey_key__chg_field_targetkey_value.py
new file mode 100644
index 000000000..b99480a2b
--- /dev/null
+++ b/ishtar_common/migrations/0028_auto__chg_field_targetkey_key__chg_field_targetkey_value.py
@@ -0,0 +1,319 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Changing field 'TargetKey.key'
+ db.alter_column('ishtar_common_targetkey', 'key', self.gf('django.db.models.fields.TextField')(default=1))
+
+ # Changing field 'TargetKey.value'
+ db.alter_column('ishtar_common_targetkey', 'value', self.gf('django.db.models.fields.TextField')(null=True))
+
+ def backwards(self, orm):
+
+ # Changing field 'TargetKey.key'
+ db.alter_column('ishtar_common_targetkey', 'key', self.gf('django.db.models.fields.TextField')(null=True))
+
+ # User chose to not deal with backwards NULL issues for 'TargetKey.value'
+ raise RuntimeError("Cannot reverse this migration. 'TargetKey.value' and its values cannot be restored.")
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'ishtar_common.arrondissement': {
+ 'Meta': {'object_name': 'Arrondissement'},
+ 'department': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '30'})
+ },
+ 'ishtar_common.author': {
+ 'Meta': {'object_name': 'Author'},
+ 'author_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.AuthorType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'to': "orm['ishtar_common.Person']"})
+ },
+ 'ishtar_common.authortype': {
+ 'Meta': {'object_name': 'AuthorType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'ishtar_common.canton': {
+ 'Meta': {'object_name': 'Canton'},
+ 'arrondissement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Arrondissement']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '30'})
+ },
+ 'ishtar_common.department': {
+ 'Meta': {'ordering': "['number']", 'object_name': 'Department'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+ 'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '3'})
+ },
+ 'ishtar_common.documenttemplate': {
+ 'Meta': {'ordering': "['associated_object_name', 'name']", 'object_name': 'DocumentTemplate'},
+ 'associated_object_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'template': ('django.db.models.fields.files.FileField', [], {'max_length': '100'})
+ },
+ 'ishtar_common.format': {
+ 'Meta': {'object_name': 'Format'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'ishtar_common.formatertype': {
+ 'Meta': {'unique_together': "(('formater_type', 'options', 'many_split'),)", 'object_name': 'FormaterType'},
+ 'formater_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'many_split': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'options': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.globalvar': {
+ 'Meta': {'ordering': "['slug']", 'object_name': 'GlobalVar'},
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}),
+ 'value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.historicalorganization': {
+ 'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalOrganization'},
+ 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'history_creator_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'history_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'history_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'history_modifier_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'history_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'history_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}),
+ 'merge_key': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}),
+ 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'organization_type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.import': {
+ 'Meta': {'object_name': 'Import'},
+ 'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'error_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'imported_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'importer_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.ImporterType']"}),
+ 'result_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'seconds_remaining': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'skip_lines': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'state': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '2'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.IshtarUser']"})
+ },
+ 'ishtar_common.importercolumn': {
+ 'Meta': {'object_name': 'ImporterColumn'},
+ 'col_number': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'columns'", 'to': "orm['ishtar_common.ImporterType']"}),
+ 'regexp_pre_filter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Regexp']", 'null': 'True', 'blank': 'True'}),
+ 'required': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'ishtar_common.importerdefault': {
+ 'Meta': {'object_name': 'ImporterDefault'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'defaults'", 'to': "orm['ishtar_common.ImporterType']"}),
+ 'target': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'ishtar_common.importerdefaultvalues': {
+ 'Meta': {'object_name': 'ImporterDefaultValues'},
+ 'default_target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'default_values'", 'to': "orm['ishtar_common.ImporterDefault']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'target': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'ishtar_common.importerduplicatefield': {
+ 'Meta': {'object_name': 'ImporterDuplicateField'},
+ 'column': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'duplicate_fields'", 'to': "orm['ishtar_common.ImporterColumn']"}),
+ 'field_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'ishtar_common.importertype': {
+ 'Meta': {'object_name': 'ImporterType'},
+ 'associated_models': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_template': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['ishtar_common.IshtarUser']", 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.importtarget': {
+ 'Meta': {'object_name': 'ImportTarget'},
+ 'column': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'targets'", 'to': "orm['ishtar_common.ImporterColumn']"}),
+ 'formater_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.FormaterType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'regexp_filter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Regexp']", 'null': 'True', 'blank': 'True'}),
+ 'target': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'ishtar_common.ishtaruser': {
+ 'Meta': {'object_name': 'IshtarUser', '_ormbases': ['auth.User']},
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ishtaruser'", 'unique': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
+ },
+ 'ishtar_common.itemkey': {
+ 'Meta': {'object_name': 'ItemKey'},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Import']", 'null': 'True', 'blank': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ 'ishtar_common.organization': {
+ 'Meta': {'object_name': 'Organization'},
+ 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'merge_candidate': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_candidate_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Organization']"}),
+ 'merge_exclusion': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_exclusion_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Organization']"}),
+ 'merge_key': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}),
+ 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'organization_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.OrganizationType']"}),
+ 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.organizationtype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'OrganizationType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'ishtar_common.person': {
+ 'Meta': {'object_name': 'Person'},
+ 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'attached_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'members'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'merge_candidate': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_candidate_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'merge_exclusion': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'merge_exclusion_rel_+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'merge_key': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}),
+ 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'person_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ishtar_common.PersonType']", 'symmetrical': 'False'}),
+ 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'raw_name': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}),
+ 'surname': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}),
+ 'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.persontype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'PersonType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'ishtar_common.regexp': {
+ 'Meta': {'object_name': 'Regexp'},
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'regexp': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ },
+ 'ishtar_common.sourcetype': {
+ 'Meta': {'object_name': 'SourceType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'ishtar_common.supporttype': {
+ 'Meta': {'object_name': 'SupportType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'ishtar_common.targetkey': {
+ 'Meta': {'unique_together': "(('target', 'value'),)", 'object_name': 'TargetKey'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_set': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'key': ('django.db.models.fields.TextField', [], {}),
+ 'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'keys'", 'to': "orm['ishtar_common.ImportTarget']"}),
+ 'value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.town': {
+ 'Meta': {'ordering': "['numero_insee']", 'object_name': 'Town'},
+ 'canton': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Canton']", 'null': 'True', 'blank': 'True'}),
+ 'center': ('django.contrib.gis.db.models.fields.PointField', [], {'srid': '27572', 'null': 'True', 'blank': 'True'}),
+ 'departement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'numero_insee': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '6'}),
+ 'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['ishtar_common'] \ No newline at end of file
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 24b64bec0..20b85e614 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -22,6 +22,7 @@ Models description
"""
from cStringIO import StringIO
import copy
+import csv
import datetime
from PIL import Image
from importlib import import_module
@@ -33,6 +34,7 @@ import unicodecsv
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist, ValidationError
+from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import validate_slug
from django.core.urlresolvers import reverse, NoReverseMatch
@@ -51,11 +53,12 @@ from django.contrib import admin
from simple_history.models import HistoricalRecords as BaseHistoricalRecords
+from ishtar_common.unicode_csv import UnicodeWriter
from ishtar_common.ooo_replace import ooo_replace
from ishtar_common.model_merging import merge_model_objects
from ishtar_common.utils import get_cache
-from ishtar_common.data_importer import Importer, ImportFormater, IntegerFormater, \
- FloatFormater, UnicodeFormater, DateFormater, TypeFormater
+from ishtar_common.data_importer import Importer, ImportFormater, \
+ IntegerFormater, FloatFormater, UnicodeFormater, DateFormater, TypeFormater
def post_save_user(sender, **kwargs):
user = kwargs['instance']
@@ -388,7 +391,7 @@ class GeneralType(models.Model):
self.add_key(key)
def get_keys(self):
- keys = []
+ keys = [self.txt_idx]
content_type = ContentType.objects.get_for_model(self.__class__)
for ik in ItemKey.objects.filter(content_type=content_type,
object_id=self.pk).all():
@@ -1168,7 +1171,8 @@ class ImportTarget(models.Model):
self.target.split('__'))
def get_choices(self):
- if not self.associated_model or not hasattr(self.associated_model, 'get_types'):
+ if not self.associated_model or not hasattr(self.associated_model,
+ 'get_types'):
return []
return self.associated_model.get_types()
@@ -1179,8 +1183,8 @@ class TargetKey(models.Model):
them in ItemKey table
"""
target = models.ForeignKey(ImportTarget, related_name='keys')
- key = models.TextField(_(u"Key"), blank=True, null=True)
- value = models.TextField(_(u"Value"))
+ key = models.TextField(_(u"Key"))
+ value = models.TextField(_(u"Value"), blank=True, null=True)
is_set = models.BooleanField(_(u"Is set"), default=False)
class Meta:
@@ -1189,6 +1193,29 @@ class TargetKey(models.Model):
def __unicode__(self):
return u" - ".join([unicode(self.target), self.key[:50]])
+ def save(self, *args, **kwargs):
+ obj = super(TargetKey, self).save(*args, **kwargs)
+ if not self.value:
+ return obj
+ associated_model = self.target.associated_model
+ if associated_model and hasattr(self.target.associated_model,
+ "add_key"):
+ v = None
+ # pk is given
+ try:
+ pk = int(self.value)
+ v = self.target.associated_model.objects.get(
+ pk=unicode(self.value))
+ except (ValueError, self.target.associated_model.DoesNotExist):
+ # try with txt_idx
+ try:
+ v = self.target.associated_model.objects.get(
+ txt_idx=unicode(self.value))
+ except (self.target.associated_model.DoesNotExist):
+ pass
+ if v:
+ v.add_key(self.key)
+ return obj
TARGET_MODELS = [
('OrganizationType', _(u"Organization type")),
('SourceType', _(u"Source type")),
@@ -1279,7 +1306,10 @@ IMPORT_STATE = (("C", _(u"Created")),
("A", _(u"Analysed")),
("P", _(u"Import pending")),
("IP", _(u"Import in progress")),
- ("F", _(u"Finished")))
+ ("FE", _(u"Finished with errors")),
+ ("F", _(u"Finished")),
+ ("AC", _(u"Archived")),
+ )
IMPORT_STATE_DCT = dict(IMPORT_STATE)
@@ -1325,6 +1355,8 @@ class Import(models.Model):
if self.state == 'A':
actions.append(('A', _(u"Re-analyse")))
actions.append(('I', _(u"Launch import")))
+ if self.state in ('F', 'FE'):
+ actions.append(('AC', _(u"Archive")))
actions.append(('D', _(u"Delete")))
return actions
@@ -1363,6 +1395,33 @@ class Import(models.Model):
self.state = 'A'
self.save()
+ def importation(self):
+ self.state = 'IP'
+ self.save()
+ importer = self.get_importer_instance()
+ importer.importation(self.data_table)
+ if importer.errors:
+ self.state = 'FE'
+ error_file = None
+
+ filename = slugify(self.importer_type.name) + ".csv"
+ now = datetime.datetime.now().isoformat('-'
+ ).replace(':','')
+ error_file = '.'.join(filename.split('.')[:-1]) \
+ + "_errors_%s.csv" % now
+ error_file = os.sep.join([self.error_file.storage.location,
+ error_file])
+ with open(error_file, 'w') as fle:
+ fle.write(importer.get_csv_errors().encode('utf-8'))
+ self.error_file = File(open(fle.name))
+ else:
+ self.state = 'F'
+ self.save()
+
+ def archive(self):
+ self.state = 'AC'
+ self.save()
+
class Organization(Address, Merge, OwnPerms, ValueGetter):
TABLE_COLS = ('name', 'organization_type',)
name = models.CharField(_(u"Name"), max_length=300)
diff --git a/ishtar_common/templates/ishtar/import_list.html b/ishtar_common/templates/ishtar/import_list.html
index 76fc1cd72..40bc019ad 100644
--- a/ishtar_common/templates/ishtar/import_list.html
+++ b/ishtar_common/templates/ishtar/import_list.html
@@ -11,9 +11,10 @@
<table>
<tr>
<th>{% trans "Type" %}</th>
- <th>{% trans "Filename" %}</th>
+ <th>{% trans "File" context "file" %}</th>
<th>{% trans "Creation" %}</th>
<th>{% trans "Status" %}</th>
+ <th>{% trans "Action" %}</th>
</tr>
{% for import in object_list %}
<tr>
@@ -21,7 +22,7 @@
{{import.importer_type}}
</td>
<td>
- {{import.imported_filename}}
+ <a href='{{MEDIA_URL}}{{import.imported_file}}'>{% trans "Source file" %}</a>
</td>
<td>
{{import.creation_date}}
@@ -42,6 +43,9 @@
<a href='{% url "import_link_unmatched" import.importer_type.pk %}'>{% trans "Link unmatched items" %}</a>
{% endif %}
</td>
+ <td>{% if import.error_file %}
+ <a href='{{MEDIA_URL}}{{import.error_file}}'>{% trans "Error file" %}</a>
+ {% endif %}</td>
</tr>
{% endfor %}
</table>
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 0d7389949..b005659db 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -886,7 +886,7 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):
def get_queryset(self):
user = models.IshtarUser.objects.get(pk=self.request.user.pk)
- return self.model.objects.filter(user=user).exclude(state='F'
+ return self.model.objects.filter(user=user).exclude(state='AC'
).order_by('-creation_date')
def post(self, request, *args, **kwargs):
@@ -908,13 +908,17 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):
imprt.delete()
elif action == 'A':
imprt.initialize()
+ elif action == 'I':
+ imprt.importation()
+ elif action == 'AC':
+ imprt.archive()
return HttpResponseRedirect(reverse(self.current_url))
class ImportOldListView(ImportListView):
current_url = 'old_imports'
def get_queryset(self):
user = models.IshtarUser.objects.get(pk=self.request.user.pk)
- return self.model.objects.filter(user=user, state='F'
+ return self.model.objects.filter(user=user, state='AC'
).order_by('-creation_date')
class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):