diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CHANGES.md | 16 | ||||
-rw-r--r-- | archaeological_context_records/models.py | 10 | ||||
-rw-r--r-- | archaeological_files/forms.py | 55 | ||||
-rw-r--r-- | archaeological_files/models.py | 5 | ||||
-rw-r--r-- | archaeological_files/tests.py | 14 | ||||
-rw-r--r-- | archaeological_files_pdl/forms.py | 66 | ||||
-rw-r--r-- | archaeological_finds/models.py | 4 | ||||
-rw-r--r-- | archaeological_operations/forms.py | 57 | ||||
-rw-r--r-- | example_project/local_settings.py.gitlab-ci | 1 | ||||
-rw-r--r-- | example_project/settings.py | 37 | ||||
-rw-r--r-- | ishtar_common/admin.py | 4 | ||||
-rw-r--r-- | ishtar_common/forms.py | 23 | ||||
-rw-r--r-- | ishtar_common/migrations/0064_auto__add_field_importercolumn_label.py | 465 | ||||
-rw-r--r-- | ishtar_common/models.py | 54 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/JQueryJqGrid.html | 2 | ||||
-rw-r--r-- | ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html | 2 | ||||
-rw-r--r-- | ishtar_common/views.py | 38 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 25 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 4 | ||||
-rw-r--r-- | version.py | 2 |
21 files changed, 757 insertions, 128 deletions
diff --git a/.gitignore b/.gitignore index 947a0dfef..484d2af20 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ oook_replace .cache dist ishtar.egg-info +.idea diff --git a/CHANGES.md b/CHANGES.md index 58e3d6f36..9f671d7b4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,22 @@ Ishtar changelog ================ +0.98.10 (2016-11-03) +-------------------- + +### Features ### + +- Force regeneration of cached labels when add M2M or changing ids +- Use lazy model evaluation for fixed type constraints +- Imports: add label to column definitions +- Use spatialite for tests +- Change default logging conf + +### Bug fixes ### + +- JQueryJqGrid: by default sorting is made using ordering in meta (fixes serious + performance issues) + 0.98.9 (2016-10-23) ------------------- diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index bbfb410f8..3f4dc1598 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -121,13 +121,13 @@ post_delete.connect(post_save_cache, sender=IdentificationType) class ContextRecord(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): SHOW_URL = 'show-contextrecord' SLUG = 'contextrecord' - TABLE_COLS = ['parcel.town', 'operation.year', - 'operation.operation_code', + TABLE_COLS = ['parcel__town', 'operation__year', + 'operation__operation_code', 'label', 'unit'] if settings.COUNTRY == 'fr': - TABLE_COLS.insert(1, 'operation.code_patriarche') + TABLE_COLS.insert(1, 'operation__code_patriarche') TABLE_COLS_FOR_OPE = ['label', 'parcel', 'unit', - 'datings.period', 'description'] + 'datings__period', 'description'] TABLE_COLS_FOR_OPE_LBL = {'section__parcel_number': _("Parcel")} CONTEXTUAL_TABLE_COLS = { 'full': { @@ -140,6 +140,7 @@ class ContextRecord(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): EXTRA_REQUEST_KEYS = { 'parcel__town': 'parcel__town__pk', 'operation__year': 'operation__year__contains', + 'year': 'operation__year__contains', 'operation__code_patriarche': 'operation__code_patriarche', 'operation__operation_code': 'operation__operation_code', 'datings__period': 'datings__period__pk', @@ -363,6 +364,7 @@ class ContextRecord(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): self.auto_external_id = True self.external_id = external_id if updated: + self._cached_label_checked = False self.save() return returned diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 26b839940..42a645171 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -28,8 +28,9 @@ from django.core import validators from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe -from ishtar_common.models import Person, PersonType, Organization, \ - OrganizationType, valid_id, Department +from ishtar_common.models import Person, Organization, \ + valid_id, Department, person_type_pks_lazy, \ + person_type_pk_lazy, organization_type_pks_lazy from archaeological_operations.models import ActType, AdministrativeAct, \ OperationType import models @@ -38,15 +39,9 @@ from ishtar_common.forms import FinalForm, get_now, reverse_lazy, TableSelect, \ from ishtar_common.forms_common import get_town_field from archaeological_operations.forms import AdministrativeActOpeForm, \ AdministrativeActOpeFormSelection, \ - ParcelField, SLICING, HEAD_SCIENTIST, SRA_AGENT, AdministrativeActModifForm + ParcelField, SLICING, AdministrativeActModifForm from ishtar_common import widgets -GENERAL_CONTRACTOR, created = PersonType.objects.get_or_create( - txt_idx='general_contractor') - -GENERAL_CONTRACTOR_ORGA, created = OrganizationType.objects.get_or_create( - txt_idx='general_contractor') - class FileSelect(TableSelect): year = forms.IntegerField(label=_("Year")) @@ -70,21 +65,22 @@ class FileSelect(TableSelect): label=_(u"In charge"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', - args=[SRA_AGENT.pk]), + args=[person_type_pk_lazy('sra_agent')]), associated_model=Person), validators=[valid_id(Person)]) general_contractor = forms.IntegerField( label=_(u"General contractor"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', - args=[GENERAL_CONTRACTOR.pk]), + args=[person_type_pk_lazy('general_contractor')]), associated_model=Person), validators=[valid_id(Person)]) general_contractor__attached_to = forms.IntegerField( label=_(u"Organization of general contractor"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization', - args=[GENERAL_CONTRACTOR_ORGA.pk]), + args=[organization_type_pks_lazy([ + 'general_contractor'])]), associated_model=Organization), validators=[valid_id(Organization)]) history_creator = forms.IntegerField( @@ -205,8 +201,10 @@ class FileFormGeneral(ManageOldType, forms.Form): in_charge = forms.IntegerField( label=_("Person in charge"), widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-person', args=[SRA_AGENT.pk]), - limit={'person_types': [SRA_AGENT.pk]}, + reverse_lazy('autocomplete-person', args=[ + person_type_pks_lazy(['sra_agent'])]), + limit={'person_types': [ + person_type_pk_lazy('sra_agent')]}, associated_model=Person, new=True), validators=[valid_id(Person)]) year = forms.IntegerField(label=_("Year"), @@ -272,12 +270,6 @@ class FileFormGeneralRO(FileFormGeneral): _(u"Another file with this numeric id exists.")) return cleaned_data -RESPONSIBLE_PLANNING_SERVICE, created = PersonType.objects.get_or_create( - txt_idx='responsible_planning_service') - -RESPONSIBLE_PLANNING_SERVICE_ORGA, created = \ - OrganizationType.objects.get_or_create(txt_idx='planning_service') - class FileFormPreventive(ManageOldType, forms.Form): form_label = _(u"Preventive informations") @@ -290,10 +282,10 @@ class FileFormPreventive(ManageOldType, forms.Form): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', - args=[PersonType.objects.get(txt_idx='general_contractor').pk] + args=[person_type_pks_lazy(['general_contractor'])] ), limit={'person_types': [ - PersonType.objects.get(txt_idx='general_contractor').pk]}, + person_type_pk_lazy('general_contractor')]}, associated_model=Person, new=True), validators=[valid_id(Person)]) responsible_town_planning_service = forms.IntegerField( @@ -302,10 +294,11 @@ class FileFormPreventive(ManageOldType, forms.Form): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', - args=[RESPONSIBLE_PLANNING_SERVICE.pk] + args=[person_type_pks_lazy(['responsible_planning_service'])] ), limit={'person_types': [ - RESPONSIBLE_PLANNING_SERVICE.pk]}, + person_type_pk_lazy('responsible_planning_service') + ]}, associated_model=Person, new=True), validators=[valid_id(Person)]) permit_type = forms.ChoiceField(label=_(u"Permit type"), required=False, @@ -351,10 +344,9 @@ class FileFormResearch(ManageOldType, forms.Form): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', - args=["_".join([unicode(HEAD_SCIENTIST.pk), - unicode(SRA_AGENT.pk)])]), - limit={'person_types': [unicode(HEAD_SCIENTIST.pk), - unicode(SRA_AGENT.pk)]}, + args=[person_type_pks_lazy(['head_scientist', 'sra_agent'])]), + limit={'person_types': [person_type_pk_lazy('head_scientist'), + person_type_pk_lazy('sra_agent')]}, associated_model=Person, new=True), label=_(u"Scientist in charge")) requested_operation_type = forms.ChoiceField( @@ -454,8 +446,7 @@ class AdministrativeActFileSelect(TableSelect): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', - args=[ - PersonType.objects.get(txt_idx='general_contractor').pk]), + args=[person_type_pk_lazy('general_contractor')]), associated_model=Person), validators=[valid_id(Person)]) associated_file__general_contractor__attached_to = forms.IntegerField( @@ -463,7 +454,7 @@ class AdministrativeActFileSelect(TableSelect): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-organization', - args=[GENERAL_CONTRACTOR_ORGA.pk]), + args=[organization_type_pks_lazy(['general_contractor'])]), associated_model=Organization), validators=[valid_id(Organization)]) associated_file__numeric_reference = forms.IntegerField( @@ -476,7 +467,7 @@ class AdministrativeActFileSelect(TableSelect): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', - args=[SRA_AGENT.pk]), + args=[person_type_pk_lazy('sra_agent')]), associated_model=Person), validators=[valid_id(Person)]) associated_file__permit_reference = forms.CharField( diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 623eb1dee..1d8317b31 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -521,6 +521,7 @@ class File(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter, self.auto_external_id = True self.external_id = external_id if updated: + self._cached_label_checked = False self.save() return returned @@ -536,9 +537,9 @@ post_save.connect(cached_label_changed, sender=File) class FileByDepartment(models.Model): - ''' + """ Database view for dashboard - ''' + """ file = models.ForeignKey(File, verbose_name=_(u"File")) department = models.ForeignKey(Department, verbose_name=_(u"Department"), blank=True, null=True) diff --git a/archaeological_files/tests.py b/archaeological_files/tests.py index dfaa1fb09..4a09e1caa 100644 --- a/archaeological_files/tests.py +++ b/archaeological_files/tests.py @@ -86,6 +86,20 @@ class FileTest(TestCase, FileInit): u"{}-{}".format(self.item.year, self.item.numeric_reference)) + def testCachedLabel(self): + lbls = ['No town', self.item.external_id, + self.item.internal_reference] + lbl = settings.JOINT.join(lbls) + self.assertEqual(self.item.cached_label, lbl) + default_town = Town.objects.create(name="Paris", numero_insee='75001') + self.item.towns.add(default_town) + # manually done inside wizards + self.item._cached_label_checked = False + self.item.save() + lbls[0] = "Paris" + lbl = settings.JOINT.join(lbls) + self.assertEqual(self.item.cached_label, lbl) + def testAddAndGetHistorized(self): """ Test correct new version and correct access to history diff --git a/archaeological_files_pdl/forms.py b/archaeological_files_pdl/forms.py index 99dc97137..cf241aa18 100644 --- a/archaeological_files_pdl/forms.py +++ b/archaeological_files_pdl/forms.py @@ -24,15 +24,12 @@ from django.core import validators from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from ishtar_common.models import Person, Town, Department, valid_id +from ishtar_common.models import Person, Town, Department, valid_id, \ + person_type_pk_lazy, person_type_pks_lazy, organization_type_pks_lazy, \ + organization_type_pk_lazy from archaeological_files import models from ishtar_common.forms import get_now, reverse_lazy, ManageOldType -from archaeological_files.forms import GENERAL_CONTRACTOR, \ - GENERAL_CONTRACTOR_ORGA, RESPONSIBLE_PLANNING_SERVICE, \ - RESPONSIBLE_PLANNING_SERVICE_ORGA - -from archaeological_operations.forms import SRA_AGENT from ishtar_common import widgets @@ -135,10 +132,10 @@ class FileFormResearchAddress(forms.Form): class PersonOrgaForm(forms.Form): PERSON_FIELD = 'TO BE DEFINED' - PERSON_TYPE = GENERAL_CONTRACTOR + PERSON_TYPE_PK = person_type_pk_lazy('general_contractor') PERSON_LABEL = "" ORGA_FIELD = 'TO BE DEFINED' - ORGA_TYPE = GENERAL_CONTRACTOR_ORGA + ORGA_TYPE_PK = organization_type_pk_lazy('general_contractor') ORGA_LABEL = "" def _media(self): @@ -205,10 +202,10 @@ class PersonOrgaForm(forms.Form): initial=initial.get(self.PERSON_FIELD, None), widget=widgets.JQueryPersonOrganization( reverse_lazy('autocomplete-person', - args=[self.PERSON_TYPE.pk]), + args=[self.PERSON_TYPE_PK]), reverse_lazy('person_create'), model=Person, - limit={'person_types': [self.PERSON_TYPE.pk], + limit={'person_types': [self.PERSON_TYPE_PK], 'attached_to__isnull': True}, js_template='ishtar/blocks/JQueryNaturalPerson.js', new=True), @@ -220,10 +217,10 @@ class PersonOrgaForm(forms.Form): initial=initial.get(self.ORGA_FIELD, None), widget=widgets.JQueryPersonOrganization( reverse_lazy('autocomplete-organization', - args=[self.ORGA_TYPE.pk]), + args=[self.ORGA_TYPE_PK]), reverse_lazy('organization_create'), model=models.Organization, - limit={'organization_type': [self.ORGA_TYPE.pk]}, + limit={'organization_type': [self.ORGA_TYPE_PK]}, js_template='ishtar/blocks/JQueryCorporationPerson.js', new=True), validators=[valid_id(models.Organization)]) @@ -238,12 +235,15 @@ class FileFormGeneralContractor(PersonOrgaForm): required=False, widget=widgets.JQueryPersonOrganization( reverse_lazy('autocomplete-organization', - args=[GENERAL_CONTRACTOR_ORGA.pk]), + args=[ + organization_type_pks_lazy(['general_contractor'])] + ), reverse_lazy('organization_create'), model=models.Organization, limit={ - 'organization_type': [GENERAL_CONTRACTOR_ORGA.pk] - }, + 'organization_type': [ + organization_type_pk_lazy('general_contractor') + ]}, js_template='ishtar/blocks/JQueryCorporationPerson.js', new=True), validators=[valid_id(models.Organization)] @@ -253,9 +253,13 @@ class FileFormGeneralContractor(PersonOrgaForm): required=False, widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', - args=[GENERAL_CONTRACTOR.pk]), + args=[ + person_type_pks_lazy(['general_contractor']) + ]), associated_model=Person, - limit={'person_types': [GENERAL_CONTRACTOR.pk]}, + limit={'person_types': [ + person_type_pk_lazy(['general_contractor']) + ]}, dynamic_limit=['general_contractor'], url_new='new-person-noorga', new=True), @@ -263,10 +267,10 @@ class FileFormGeneralContractor(PersonOrgaForm): ) PERSON_FIELD = 'general_contractor' - PERSON_TYPE = GENERAL_CONTRACTOR + PERSON_TYPE_PK = person_type_pk_lazy('general_contractor') PERSON_LABEL = _(u"General contractor") ORGA_FIELD = 'corporation_general_contractor' - ORGA_TYPE = GENERAL_CONTRACTOR_ORGA + ORGA_TYPE_PK = organization_type_pk_lazy('general_contractor') ORGA_LABEL = _(u"General contractor") def __init__(self, *args, **kwargs): @@ -327,10 +331,10 @@ class FileFormGeneralContractor(PersonOrgaForm): initial=initial.get(self.PERSON_FIELD, None), widget=widgets.JQueryPersonOrganization( reverse_lazy('autocomplete-person', - args=[self.PERSON_TYPE.pk]), + args=[self.PERSON_TYPE_PK]), reverse_lazy('person_create'), model=Person, - limit={'person_types': [self.PERSON_TYPE.pk], + limit={'person_types': [self.PERSON_TYPE_PK], 'attached_to__isnull': True}, js_template='ishtar/blocks/JQueryNaturalPerson.js', new=True), @@ -349,12 +353,14 @@ class FileFormPlanningService(forms.Form): label=_("Planning service"), required=False, widget=widgets.JQueryPersonOrganization( - reverse_lazy('autocomplete-organization', - args=[RESPONSIBLE_PLANNING_SERVICE_ORGA.pk]), + reverse_lazy( + 'autocomplete-organization', + args=[organization_type_pks_lazy(['planning_service'])]), reverse_lazy('organization_create'), model=models.Organization, limit={ - 'organization_type': [RESPONSIBLE_PLANNING_SERVICE_ORGA.pk] + 'organization_type': + [organization_type_pk_lazy(['planning_service'])], }, js_template='ishtar/blocks/JQueryCorporationPerson.js', new=True), @@ -365,9 +371,13 @@ class FileFormPlanningService(forms.Form): required=False, widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-person', - args=[RESPONSIBLE_PLANNING_SERVICE.pk]), + args=[ + person_type_pks_lazy( + ['responsible_planning_service'])]), associated_model=Person, - limit={'person_types': [RESPONSIBLE_PLANNING_SERVICE.pk]}, + limit={'person_types': [ + person_type_pk_lazy('responsible_planning_service') + ]}, dynamic_limit=['planning_service'], url_new='new-person-noorga', new=True), @@ -384,10 +394,10 @@ class FileFormInstruction(forms.Form): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person', - args=[SRA_AGENT.pk]), + args=[person_type_pks_lazy(["sra_agent"])]), limit={ 'person_types': [ - SRA_AGENT.pk] + person_type_pk_lazy('sra_agent')] }, associated_model=Person, new=True), validators=[valid_id(Person)]) diff --git a/archaeological_finds/models.py b/archaeological_finds/models.py index 5799d0e9a..aa5eacc30 100644 --- a/archaeological_finds/models.py +++ b/archaeological_finds/models.py @@ -269,6 +269,7 @@ class BaseFind(BaseHistorizedItem, OwnPerms): self.auto_external_id = True self.external_id = external_id if updated: + self._cached_label_checked = False self.save() return returned @@ -653,6 +654,7 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): self.auto_external_id = True self.external_id = external_id if updated: + self._cached_label_checked = False self.save() return @@ -671,6 +673,7 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): self.index = q.aggregate(Max('index'))['index__max'] + 1 else: self.index = 1 + self._cached_label_checked = False self.save() for base_find in self.base_finds.filter( context_record__operation__pk__isnull=False).all(): @@ -689,6 +692,7 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem): modified = True if modified: base_find.skip_history_when_saving = True + base_find._cached_label_checked = False base_find.save() # if not base_find.material_index: # idx = BaseFind.objects\ diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index a12f245cb..37c35f4be 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -34,7 +34,9 @@ from django.utils.translation import ugettext_lazy as _, pgettext_lazy from django.utils.safestring import mark_safe from ishtar_common.models import valid_id, PersonType, Person, Town, \ - DocumentTemplate, Organization, OrganizationType, get_current_profile + DocumentTemplate, Organization, OrganizationType, get_current_profile, \ + person_type_pks_lazy, person_type_pk_lazy, organization_type_pks_lazy, \ + organization_type_pk_lazy from ishtar_common.wizards import MultiValueDict @@ -448,12 +450,6 @@ class RecordRelationsForm(ManageOldType, forms.Form): RecordRelationsFormSet = formset_factory(RecordRelationsForm, can_delete=True) RecordRelationsFormSet.form_label = _(u"Relations") -SRA_AGENT, created = PersonType.objects.get_or_create(txt_idx='sra_agent') -HEAD_SCIENTIST, created = PersonType.objects.get_or_create( - txt_idx='head_scientist') - -OPERATOR, created = OrganizationType.objects.get_or_create(txt_idx='operator') - class OperationSelect(TableSelect): year = forms.IntegerField(label=_("Year")) @@ -476,22 +472,23 @@ class OperationSelect(TableSelect): widget=widgets.JQueryAutoComplete( reverse_lazy( 'autocomplete-person-permissive', - args=["_".join( - [unicode(PersonType.objects.get(txt_idx='sra_agent').pk)])] + args=[person_type_pks_lazy(['sra_agent'])] ), associated_model=Person), label=_(u"In charge")) scientist = forms.IntegerField( widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-person-permissive', - args=["_".join([unicode(HEAD_SCIENTIST.pk), - unicode(SRA_AGENT.pk)])]), + reverse_lazy( + 'autocomplete-person-permissive', + args=[person_type_pks_lazy(['sra_agent', 'head_scientist'])]), associated_model=Person), label=_(u"Scientist in charge")) operator = forms.IntegerField( label=_("Operator"), widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-organization', args=[OPERATOR.pk]), + reverse_lazy( + 'autocomplete-organization', + args=[organization_type_pks_lazy(['operator'])]), associated_model=Organization), validators=[valid_id(Organization)]) # operator_reference = forms.CharField(label=_(u"Operator reference"), @@ -762,18 +759,21 @@ class OperationFormGeneral(ManageOldType, forms.Form): scientist = forms.IntegerField( label=_("Head scientist"), widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-person', - args=["_".join([unicode(HEAD_SCIENTIST.pk), - unicode(SRA_AGENT.pk)])]), + reverse_lazy( + 'autocomplete-person', + args=[person_type_pks_lazy(['head_scientist', 'sra_agent'])]), associated_model=Person, - limit={'person_types': (HEAD_SCIENTIST.pk, SRA_AGENT.pk)}, + limit={ + 'person_types': (person_type_pk_lazy('head_scientist'), + person_type_pk_lazy('sra_agent'))}, new=True), validators=[valid_id(Person)], required=False) operator = forms.IntegerField( label=_("Operator"), widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-organization', args=[OPERATOR.pk]), - limit={'organization_type': (OPERATOR.pk,)}, + reverse_lazy('autocomplete-organization', + args=[organization_type_pk_lazy('operator')]), + limit={'organization_type': organization_type_pk_lazy('operator')}, associated_model=Organization, new=True), validators=[valid_id(Organization)], required=False) operator_reference = forms.CharField(label=_(u"Operator reference"), @@ -781,10 +781,12 @@ class OperationFormGeneral(ManageOldType, forms.Form): in_charge = forms.IntegerField( label=_("In charge"), widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-person', - args=["_".join([unicode(SRA_AGENT.pk)])]), + reverse_lazy( + 'autocomplete-person', + args=[person_type_pks_lazy(['sra_agent'])]), associated_model=Person, - limit={'person_types': [SRA_AGENT.pk]}, new=True), + limit={'person_types': [person_type_pk_lazy('sra_agent')]}, + new=True), validators=[valid_id(Person)], required=False) surface = forms.IntegerField( required=False, widget=widgets.AreaWidget, @@ -812,10 +814,13 @@ class OperationFormGeneral(ManageOldType, forms.Form): cira_rapporteur = forms.IntegerField( label=u"Rapporteur CIRA", widget=widgets.JQueryAutoComplete( - reverse_lazy('autocomplete-person', - args=["_".join([unicode(HEAD_SCIENTIST.pk), - unicode(SRA_AGENT.pk)])]), - limit={'person_types': [SRA_AGENT.pk, HEAD_SCIENTIST.pk]}, + reverse_lazy( + 'autocomplete-person', + args=[person_type_pks_lazy(['head_scientist', + 'sra_agent'])]), + limit={'person_types': [ + person_type_pk_lazy('sra_agent'), + person_type_pk_lazy('head_scientist')]}, associated_model=Person, new=True), validators=[valid_id(Person)], required=False) documentation_deadline = forms.DateField( diff --git a/example_project/local_settings.py.gitlab-ci b/example_project/local_settings.py.gitlab-ci index 7f4bcefa1..81196b4a0 100644 --- a/example_project/local_settings.py.gitlab-ci +++ b/example_project/local_settings.py.gitlab-ci @@ -12,3 +12,4 @@ DATABASES = { LOGFILE = '/tmp/ishtar.log' PROJECT_SLUG = "CI-instance" +USE_SPATIALITE_FOR_TESTS = False diff --git a/example_project/settings.py b/example_project/settings.py index 128befe5a..a191b83b3 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -10,6 +10,7 @@ DEBUG_TOOLBAR = False TEMPLATE_DEBUG = DEBUG SQL_DEBUG = False DJANGO_EXTENSIONS = False +USE_SPATIALITE_FOR_TESTS = True if "test" in sys.argv: sys.path.insert(0, '..') @@ -155,6 +156,12 @@ INSTALLED_APPS = [ LOGFILE = '' +default_handler = { + 'handlers': ['logfile'], + 'level': 'INFO', + 'propogate': False +} + LOGGING = { 'version': 1, 'disable_existing_loggers': False, @@ -178,24 +185,24 @@ LOGGING = { }, }, 'loggers': { - # Again, default Django configuration to email unhandled exceptions 'django.request': { - 'handlers': ['mail_admins'], + 'handlers': ['mail_admins', 'logfile'], 'level': 'ERROR', 'propagate': True, }, - # Might as well log any errors anywhere else in Django 'django': { 'handlers': ['logfile'], 'level': 'ERROR', 'propagate': False, }, - # Your own app - this assumes all your logger names start with "myapp." - 'chimere': { - 'handlers': ['logfile'], - 'level': 'WARNING', # Or maybe INFO or DEBUG - 'propogate': False - }, + 'ishtar_pdl': default_handler, + 'ishtar_common': default_handler, + 'archaeological_files_pdl': default_handler, + 'archaeological_files': default_handler, + 'archaeological_operations': default_handler, + 'archaeological_context_records': default_handler, + 'archaeological_warehouse': default_handler, + 'archaeological_finds': default_handler, }, } @@ -230,6 +237,10 @@ except ImportError, e: if 'test' in sys.argv: SOUTH_TESTS_MIGRATE = False + if USE_SPATIALITE_FOR_TESTS: + DATABASES['default']['ENGINE'] = \ + 'django.contrib.gis.db.backends.spatialite' + PROJECT_SLUG = locals().get('PROJECT_SLUG', 'default') if LOGFILE: @@ -243,6 +254,11 @@ INTERNAL_IPS = ('127.0.0.1',) JQUERY_URL = STATIC_URL + "js/jquery.min.js" JQUERY_UI_URL = STATIC_URL + "js/jquery-ui/" +if DEBUG: + # make all loggers use the console + for logger in LOGGING['loggers']: + LOGGING['loggers'][logger]['handlers'] += ['console'] + if DJANGO_EXTENSIONS: INSTALLED_APPS.append('django_extensions') @@ -272,3 +288,6 @@ if SQL_DEBUG: 'level': 'DEBUG', 'handlers': ['console'], } + +if 'test' in sys.argv: + PROJECT_SLUG += "-test" diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index fb0ab1170..aa04a7b1c 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2010-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -202,7 +202,7 @@ class ImportTargetInline(admin.TabularInline): class ImporterColumnAdmin(admin.ModelAdmin): - list_display = ('importer_type', 'col_number', 'description', + list_display = ('label', 'importer_type', 'col_number', 'description', 'targets_lbl', 'duplicate_fields_lbl', 'required') list_filter = ('importer_type',) inlines = (ImporterDuplicateFieldInline, ImportTargetInline) diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index b0e8cb43c..043b03f61 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -31,6 +31,10 @@ from django.utils import formats from django.utils.functional import lazy from django.utils.translation import ugettext_lazy as _ +import models +import widgets + + # from formwizard.forms import NamedUrlSessionFormWizard @@ -44,10 +48,23 @@ class NamedUrlSessionFormWizard(forms.Form): def rindex(self, idx): return self.url_name.rindex(idx) -import models -import widgets -reverse_lazy = lazy(reverse, unicode) +def my_reverse(*args, **kwargs): + """ + Custom reverse method in order to evaluate lazy args + """ + if 'args' in kwargs: + my_args = [] + for arg in kwargs['args']: + if callable(arg): + my_args.append(unicode(arg())) + else: + my_args.append(unicode(arg)) + kwargs['args'] = my_args + return reverse(*args, **kwargs) + + +reverse_lazy = lazy(my_reverse, unicode) regexp_name = re.compile(r"^[,:/\w\-'\"() \&\[\]@]+$", re.UNICODE) name_validator = validators.RegexValidator( diff --git a/ishtar_common/migrations/0064_auto__add_field_importercolumn_label.py b/ishtar_common/migrations/0064_auto__add_field_importercolumn_label.py new file mode 100644 index 000000000..2f2b6efcc --- /dev/null +++ b/ishtar_common/migrations/0064_auto__add_field_importercolumn_label.py @@ -0,0 +1,465 @@ +# -*- 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): + # Adding field 'ImporterColumn.label' + db.add_column('ishtar_common_importercolumn', 'label', + self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'ImporterColumn.label' + db.delete_column('ishtar_common_importercolumn', 'label') + + + 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': '100'}) + }, + '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'}), + 'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.State']", 'null': 'True', 'blank': 'True'}) + }, + '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': '100'}) + }, + 'ishtar_common.formatertype': { + 'Meta': {'ordering': "('formater_type', 'options')", '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'}), + 'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), + 'archived': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', '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': '300', '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.TextField', [], {'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': '500'}), + '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'}), + 'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'raw_phone': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}) + }, + 'ishtar_common.historicalperson': { + 'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalPerson'}, + 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), + 'archived': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}), + 'attached_to_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'contact_type': ('django.db.models.fields.CharField', [], {'max_length': '300', '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': '300', '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.TextField', [], {'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'}), + 'old_title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', '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'}), + 'raw_phone': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'salutation': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'surname': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'title_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}) + }, + 'ishtar_common.import': { + 'Meta': {'object_name': 'Import'}, + 'conservative_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "'utf-8'", 'max_length': '15'}), + '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'}), + 'imported_images': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'importer_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.ImporterType']"}), + 'match_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + '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': {'ordering': "('importer_type', 'col_number')", 'unique_together': "(('importer_type', 'col_number'),)", 'object_name': 'ImporterColumn'}, + 'col_number': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + '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']"}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + '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']"}), + 'concat': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'concat_str': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}), + 'field_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'force_new': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '100', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'unicity_keys': ('django.db.models.fields.CharField', [], {'max_length': '500', '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']"}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'concat': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'concat_str': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}), + 'force_new': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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.ishtarsiteprofile': { + 'Meta': {'ordering': "['label']", 'object_name': 'IshtarSiteProfile'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'base_find_external_id': ('django.db.models.fields.TextField', [], {'default': "'{context_record__external_id}-{label}'"}), + 'context_record': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'context_record_external_id': ('django.db.models.fields.TextField', [], {'default': "'{parcel__external_id}-{label}'"}), + 'currency': ('django.db.models.fields.CharField', [], {'default': "u'\\u20ac'", 'max_length': "'5'"}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'file_external_id': ('django.db.models.fields.TextField', [], {'default': "'{year}-{numeric_reference}'"}), + 'files': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'find': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'find_external_id': ('django.db.models.fields.TextField', [], {'default': "'{get_first_base_find__context_record__external_id}-{label}'"}), + 'homepage': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.TextField', [], {}), + 'parcel_external_id': ('django.db.models.fields.TextField', [], {'default': "'{associated_file__external_id}{operation__code_patriarche}-{town__numero_insee}-{section}{parcel_number}'"}), + 'person_raw_name': ('django.db.models.fields.TextField', [], {'default': "'{name|upper} {surname}'"}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), + 'warehouse': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'ishtar_common.ishtaruser': { + 'Meta': {'object_name': 'IshtarUser', '_ormbases': ['auth.User']}, + 'advanced_shortcut_menu': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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.operationtype': { + 'Meta': {'ordering': "['-preventive', 'order', 'label']", 'object_name': 'OperationType'}, + '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'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'preventive': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}) + }, + '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'}), + 'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), + 'archived': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', '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': '300', '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'}), + 'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_ishtar_common_organization'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), + '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.TextField', [], {'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': '500'}), + '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'}), + 'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'raw_phone': ('django.db.models.fields.TextField', [], {'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': '100'}) + }, + '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'}), + 'alt_address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'alt_address_is_prefered': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'alt_country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'alt_postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'alt_town': ('django.db.models.fields.CharField', [], {'max_length': '70', 'null': 'True', 'blank': 'True'}), + 'archived': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', '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']"}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'contact_type': ('django.db.models.fields.CharField', [], {'max_length': '300', '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': '300', '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'}), + 'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_ishtar_common_person'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), + '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.TextField', [], {'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'}), + 'old_title': ('django.db.models.fields.CharField', [], {'max_length': '100', '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'}), + 'phone2': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone3': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'phone_desc': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc2': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True', 'blank': 'True'}), + 'phone_desc3': ('django.db.models.fields.CharField', [], {'max_length': '300', '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'}), + 'raw_phone': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'salutation': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'surname': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.TitleType']", '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': '100'}) + }, + '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': '100'}) + }, + 'ishtar_common.state': { + 'Meta': {'ordering': "['number']", 'object_name': 'State'}, + '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.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': '100'}) + }, + 'ishtar_common.targetkey': { + 'Meta': {'unique_together': "(('target', 'key', 'associated_user', 'associated_import'),)", 'object_name': 'TargetKey'}, + 'associated_import': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Import']", 'null': 'True', 'blank': 'True'}), + 'associated_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.IshtarUser']", 'null': 'True', 'blank': 'True'}), + '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.titletype': { + 'Meta': {'ordering': "('label',)", 'object_name': 'TitleType'}, + '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': '100'}) + }, + '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'}), + 'imports': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'imported_ishtar_common_town'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.Import']"}), + '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 3453a53c5..72a3432f8 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -43,6 +43,7 @@ from django.db.utils import DatabaseError from django.db.models import Q, Max, Count from django.db.models.base import ModelBase from django.db.models.signals import post_save, pre_delete, post_delete +from django.utils.functional import lazy from django.utils.translation import ugettext_lazy as _, ugettext, \ pgettext_lazy @@ -66,7 +67,6 @@ from ishtar_common.data_importer import Importer, ImportFormater, \ def post_save_user(sender, **kwargs): user = kwargs['instance'] - ishtaruser = None try: q = IshtarUser.objects.filter(username=user.username) if not q.count(): @@ -334,6 +334,51 @@ class GeneralType(Cached, models.Model): return self.label @classmethod + def get_or_create(cls, slug, label=''): + """ + Get or create a new item. + + :param slug: textual id + :param label: label for initialization if the item doesn't exist (not + mandatory) + + :return: instancied item of the base class + """ + + item = cls.get_cache(slug) + if item: + return item + item, created = cls.objects.get_or_create( + txt_idx=slug, defaults={'label': label}) + return item + + @classmethod + def get_or_create_pk(cls, slug): + """ + Get an id from a slug. Create the associated item if needed. + + :param slug: textual id + + :return: id of the item (string) + """ + return unicode(cls.get_or_create(slug).pk) + + @classmethod + def get_or_create_pks(cls, slugs): + """ + Get and merge a list of ids from a slug list. Create the associated + items if needed. + + :param slugs: textual ids + + :return: string with ids separated by "_" + """ + items = [] + for slug in slugs: + items.append(str(cls.get_or_create(slug).pk)) + return u"_".join(items) + + @classmethod def get_help(cls, dct={}, exclude=[]): help_text = cls.HELP_TEXT c_rank = -1 @@ -1534,6 +1579,9 @@ class OrganizationType(GeneralType): post_save.connect(post_save_cache, sender=OrganizationType) post_delete.connect(post_save_cache, sender=OrganizationType) +organization_type_pk_lazy = lazy(OrganizationType.get_or_create_pk, unicode) +organization_type_pks_lazy = lazy(OrganizationType.get_or_create_pks, unicode) + IMPORTER_CLASSES = {} IMPORTER_CLASSES.update({ @@ -1764,6 +1812,7 @@ class ImporterColumn(models.Model): """ Import file column description """ + label = models.CharField(_(u"Label"), blank=True, null=True, max_length=200) importer_type = models.ForeignKey(ImporterType, related_name='columns') col_number = models.IntegerField(_(u"Column number"), default=1) description = models.TextField(_("Description"), blank=True, null=True) @@ -2324,6 +2373,9 @@ class PersonType(GeneralType): post_save.connect(post_save_cache, sender=PersonType) post_delete.connect(post_save_cache, sender=PersonType) +person_type_pk_lazy = lazy(PersonType.get_or_create_pk, unicode) +person_type_pks_lazy = lazy(PersonType.get_or_create_pks, unicode) + class TitleType(GeneralType): class Meta: diff --git a/ishtar_common/templates/blocks/JQueryJqGrid.html b/ishtar_common/templates/blocks/JQueryJqGrid.html index faa2d9e93..607f81f7d 100644 --- a/ishtar_common/templates/blocks/JQueryJqGrid.html +++ b/ishtar_common/templates/blocks/JQueryJqGrid.html @@ -84,7 +84,7 @@ jQuery(document).ready(function(){ {{extra_cols|safe}} ], height: 300, - sortname: 'value', + sortname: '__default__', viewrecords: true, sortorder: "asc", emptyrecords: "{{no_result}}", diff --git a/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html b/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html index 4a81a64fb..f751cebe3 100644 --- a/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html +++ b/ishtar_common/templates/ishtar/blocks/window_tables/dynamic_documents.html @@ -27,7 +27,7 @@ setTimeout( {name:'link', index:'link', width:30}, {{extra_cols|safe}} ], - sortname: 'value', + sortname: '__default__', viewrecords: true, sortorder: "asc", emptyrecords: "{{no_result}}", diff --git a/ishtar_common/views.py b/ishtar_common/views.py index bc5e5ef1d..cd34a2019 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -25,6 +25,7 @@ import cStringIO as StringIO import datetime import ho.pisa as pisa import json +import logging from markdown import markdown import optparse import re @@ -75,6 +76,8 @@ import models CSV_OPTIONS = {'delimiter': ';', 'quotechar': '"', 'quoting': csv.QUOTE_ALL} ENCODING = settings.ENCODING or 'utf-8' +logger = logging.getLogger(__name__) + def index(request): """ @@ -334,7 +337,7 @@ def update_current_item(request, item_type=None, pk=None): request.session['SHORTCUT_SEARCH'] = 'all' currents = get_current_items(request) - # reinit when descending item are not relevant + # re-init when descending item are not relevant if item_type == 'file' and currents['file'] and currents['operation'] and \ currents['operation'].associated_file != currents['file']: request.session["operation"] = '' @@ -428,7 +431,6 @@ def autocomplete_person(request, person_types=None, attached_to=None, pass if is_ishtar_user: query = query & Q(ishtaruser__isnull=False) - limit = 20 persons = models.Person.objects.filter(query)[:limit] data = json.dumps([{'id': person.pk, 'value': unicode(person)} for person in persons if person]) @@ -696,7 +698,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[], dct[k] = not dct[k] # check also for empty value with image field field_name = k.split('__')[0] - # TODO: can be improved in later evrsion of Django + # TODO: can be improved in later version of Django try: c_field = model._meta.get_field(field_name) if k.endswith('__isnull') and \ @@ -811,7 +813,6 @@ def get_item(model, func_name, default_name, extra_request_keys=[], items = model.objects.filter(query).distinct() # print(items.query) - q = request_items.get('sidx') # table cols if own_table_cols: @@ -841,7 +842,12 @@ def get_item(model, func_name, default_name, extra_request_keys=[], manual_sort_key = None order = request_items.get('sord') sign = order and order == u'desc' and "-" or '' - if q and q in request_keys: + + q = request_items.get('sidx') + if q == '__default__' and model._meta.ordering: + orders = [sign + k for k in model._meta.ordering] + items = items.order_by(*orders) + elif q and q in request_keys: ks = request_keys[q] if type(ks) not in (list, tuple): ks = [ks] @@ -859,6 +865,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[], ke = ke[0] if ke.endswith(q): manual_sort_key = ke + logger.warning("**WARN get_item - {}**: manual sort key '{" + "}'".format(func_name, q)) break if not manual_sort_key and model._meta.ordering: orders = [sign + k for k in model._meta.ordering] @@ -903,7 +911,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[], my_vals = [] for k in keys: vals = [item] - # foreign key may be splited by "." or "__" + # foreign key may be divided by "." or "__" splitted_k = [] for ky in k.split('.'): if '__' in ky: @@ -973,8 +981,9 @@ def get_item(model, func_name, default_name, extra_request_keys=[], lnk = link_template % reverse('show-' + default_name, args=[data[0], '']) except NoReverseMatch: - print '"show-' + default_name + "\" args (" + \ - unicode(data[0]) + ") url not available" + print( + '"show-' + default_name + "\" args (" + + unicode(data[0]) + ") url not available") lnk = '' res = {'id': data[0], 'link': lnk} for idx, value in enumerate(data[1:]): @@ -983,7 +992,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[], if type(table_col) not in (list, tuple): table_col = [table_col] tab_cols = [] - # foreign key may be splited by "." or "__" + # foreign key may be divided by "." or "__" for tc in table_col: if '.' in tc: tab_cols.append(tc.split('.')[-1]) @@ -1073,7 +1082,9 @@ def show_item(model, name, extra_dct=None): dct['CURRENCY'] = get_current_profile().currency dct['ENCODING'] = settings.ENCODING dct['current_window_url'] = url_name - date = 'date' in dct and dct.pop('date') + date = None + if 'date' in dct: + date = dct.pop('date') dct['window_id'] = "%s-%d-%s" % ( name, item.pk, datetime.datetime.now().strftime('%M%s')) if hasattr(item, 'history'): @@ -1306,9 +1317,7 @@ def dashboard_main(request, dct, obj_id=None, *args, **kwargs): return render_to_response('ishtar/dashboards/dashboard_main.html', dct, context_instance=RequestContext(request)) -DASHBOARD_FORMS = {} -DASHBOARD_FORMS['files'] = DashboardFormFile -DASHBOARD_FORMS['operations'] = DashboardFormOpe +DASHBOARD_FORMS = {'files': DashboardFormFile, 'operations': DashboardFormOpe} def dashboard_main_detail(request, item_name): @@ -1339,6 +1348,7 @@ def dashboard_main_detail(request, item_name): else: form = DASHBOARD_FORMS[item_name]() lbl, dashboard = None, None + dashboard_kwargs = {} if (item_name == 'files' and profile.files) \ or item_name == 'operations': dashboard_kwargs = {'slice': slicing, 'fltr': fltr, @@ -1375,7 +1385,7 @@ def dashboard_main_detail(request, item_name): def reset_wizards(request): - # dynamicaly execute each reset_wizards of each ishtar app + # dynamically execute each reset_wizards of each ishtar app for app in settings.INSTALLED_APPS: if app == 'ishtar_common': # no need for infinite recursion diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 9e656311b..1183836bc 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -431,7 +431,6 @@ class JQueryPersonOrganization(forms.TextInput): @classmethod def encode_source(cls, source): - encoded_src = '' if isinstance(source, list): encoded_src = JSONEncoder().encode(source) elif isinstance(source, str) \ @@ -516,10 +515,29 @@ class JQueryJqGrid(forms.RadioSelect): def __init__(self, source, form, associated_model, attrs={}, table_cols='TABLE_COLS', multiple=False, multiple_cols=[2], new=False, new_message="", source_full=None, - multiple_select=False): + multiple_select=False, sortname="__default__"): + """ + JQueryJqGrid widget init. + + :param source: url to get the item from -- get_item + :param form: + :param associated_model: model of the listed items + :param attrs: + :param table_cols: + :param multiple: + :param multiple_cols: + :param new: + :param new_message: + :param source_full: url to get full listing + :param multiple_select: + :param sortname: column name (model attribute) to use to sort + """ + super(JQueryJqGrid, self).__init__(attrs=attrs) self.source = source self.form = form - self.attrs = attrs + if not attrs: + attrs = {} + self.attrs = attrs.copy() self.associated_model = associated_model self.table_cols = table_cols self.multiple = multiple @@ -527,6 +545,7 @@ class JQueryJqGrid(forms.RadioSelect): self.multiple_cols = multiple_cols self.new, self.new_message = new, new_message self.source_full = source_full + self.sortname = sortname def get_cols(self, python=False): jq_col_names, extra_cols = [], [] diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index c8467ca61..c065459f6 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -553,6 +553,7 @@ class Wizard(NamedUrlWizardView): getattr(obj, k).add(adds[k]) # necessary to manage interaction between models like # material_index management for baseitems + obj._cached_label_checked = False obj.save() m2m_items = {} # clear @@ -618,6 +619,7 @@ class Wizard(NamedUrlWizardView): related_model.add(value) # necessary to manage interaction between models like # material_index management for baseitems + obj._cached_label_checked = False obj.save() # make the new object a default if self.current_obj_slug: @@ -715,7 +717,7 @@ class Wizard(NamedUrlWizardView): # and self.form_initialized: # for k in init[0]: # data[step + '-' + unicode(total_field) + '-' + k] = \ - # init[0][k] + # init[0][k] data = data or None form = super(Wizard, self).get_form(step, data, files) diff --git a/version.py b/version.py index 56f79188c..91309b62b 100644 --- a/version.py +++ b/version.py @@ -1,4 +1,4 @@ -VERSION = (0, 98, 9) +VERSION = (0, 98, 10) def get_version(): |