diff options
| -rw-r--r-- | Makefile.example | 18 | ||||
| -rw-r--r-- | example_project/urls.py | 6 | ||||
| -rw-r--r-- | ishtar_common/data_importer.py | 7 | ||||
| -rw-r--r-- | ishtar_common/forms_common.py | 16 | ||||
| -rw-r--r-- | ishtar_common/migrations/0028_auto__chg_field_targetkey_key__chg_field_targetkey_value.py | 319 | ||||
| -rw-r--r-- | ishtar_common/models.py | 73 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/import_list.html | 8 | ||||
| -rw-r--r-- | ishtar_common/views.py | 8 | 
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): | 
