summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2013-12-26 19:09:09 +0100
committerÉtienne Loks <etienne.loks@peacefrogs.net>2013-12-26 19:09:09 +0100
commit39e296ed421cce7696313dcafe75cd03d073054d (patch)
treed69858ce6408508fc2661a04e75d0a5b32d33f5a
parentbd64ebef333c1275923bf90dd69e8181e80092aa (diff)
downloadIshtar-39e296ed421cce7696313dcafe75cd03d073054d.tar.bz2
Ishtar-39e296ed421cce7696313dcafe75cd03d073054d.zip
Manage archaeological sites into forms (refs #1586)
* create new widget: multiple autocomplete field * move JS autocomplete to template * archaeological site reference made unique
-rw-r--r--archaeological_operations/forms.py34
-rw-r--r--archaeological_operations/migrations/0015_auto__add_unique_archaeologicalsite_reference.py419
-rw-r--r--archaeological_operations/models.py12
-rw-r--r--archaeological_operations/urls.py5
-rw-r--r--archaeological_operations/views.py28
-rw-r--r--ishtar_common/templates/blocks/JQueryAutocomplete.js19
-rw-r--r--ishtar_common/templates/blocks/JQueryAutocompleteMultiple.js92
-rw-r--r--ishtar_common/templatetags/replace_underscore.py10
-rw-r--r--ishtar_common/widgets.py113
-rw-r--r--ishtar_common/wizards.py30
10 files changed, 726 insertions, 36 deletions
diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py
index d9f5ece9b..0faad26a9 100644
--- a/archaeological_operations/forms.py
+++ b/archaeological_operations/forms.py
@@ -62,7 +62,7 @@ class ParcelField(forms.MultiValueField):
class ParcelForm(forms.Form):
form_label = _("Parcels")
base_model = 'parcel'
- associated_models = {'parcel':models.Parcel, 'town':models.Town}
+ associated_models = {'parcel':models.Parcel, 'town':models.Town,}
town = forms.ChoiceField(label=_("Town"), choices=(), required=False,
validators=[valid_id(models.Town)])
year = forms.IntegerField(label=_("Year"), required=False,
@@ -275,7 +275,8 @@ class OperationFormGeneral(forms.Form):
form_label = _(u"General")
associated_models = {'in_charge':Person,
'associated_file':File,
- 'operation_type':models.OperationType}
+ 'operation_type':models.OperationType,
+ 'archaeological_sites':models.ArchaeologicalSite}
currents = {'associated_file':File}
pk = forms.IntegerField(required=False, widget=forms.HiddenInput)
in_charge = forms.IntegerField(label=_("Person in charge of the operation"),
@@ -312,6 +313,10 @@ class OperationFormGeneral(forms.Form):
max_length=120, widget=forms.Textarea)
operator_reference = forms.CharField(label=_(u"Operator reference"),
required=False, max_length=20)
+ archaeological_sites = widgets.MultipleAutocompleteField(
+ model=models.ArchaeologicalSite,
+ label=_("Associated archaelogical sites"),
+ new=True, required=False)
if settings.COUNTRY == 'fr':
negative_result = forms.NullBooleanField(required=False,
label=u"Résultat considéré comme négatif")
@@ -489,6 +494,31 @@ PeriodFormset = formset_factory(PeriodForm, can_delete=True,
formset=PeriodFormSet)
PeriodFormset.form_label = _("Periods")
+class ArchaeologicalSiteForm(forms.Form):
+ reference = forms.CharField(label=_(u"Reference"), max_length=20)
+ name = forms.CharField(label=_(u"Name"), max_length=200, required=False)
+
+ def clean_reference(self):
+ reference = self.cleaned_data['reference']
+ if models.ArchaeologicalSite.objects.filter(
+ reference=reference).count():
+ raise forms.ValidationError(_(u"This reference already exists."))
+ return reference
+
+ def save(self, user):
+ dct = self.cleaned_data
+ dct['history_modifier'] = user
+ return models.ArchaeologicalSite.objects.create(**dct)
+
+class ArchaeologicalSiteSelectionForm(forms.Form):
+ form_label = _("Associated archaelogical sites")
+ archaeological_sites = forms.IntegerField(
+ widget=widgets.JQueryAutoComplete(reverse_lazy(
+ 'autocomplete-archaeologicalsite'),
+ associated_model=models.ArchaeologicalSite, new=True,
+ multiple=True),
+ label=_(u"Search"))
+
class FinalOperationClosingForm(FinalForm):
confirm_msg = " "
confirm_end_msg = _(u"Would you like to close this operation?")
diff --git a/archaeological_operations/migrations/0015_auto__add_unique_archaeologicalsite_reference.py b/archaeological_operations/migrations/0015_auto__add_unique_archaeologicalsite_reference.py
new file mode 100644
index 000000000..3982d3d4d
--- /dev/null
+++ b/archaeological_operations/migrations/0015_auto__add_unique_archaeologicalsite_reference.py
@@ -0,0 +1,419 @@
+# -*- 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 unique constraint on 'ArchaeologicalSite', fields ['reference']
+ db.create_unique('archaeological_operations_archaeologicalsite', ['reference'])
+
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'ArchaeologicalSite', fields ['reference']
+ db.delete_unique('archaeological_operations_archaeologicalsite', ['reference'])
+
+
+ models = {
+ 'archaeological_files.file': {
+ 'Meta': {'ordering': "['-year', '-numeric_reference']", 'object_name': 'File'},
+ 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'cached_label': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'creation_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.date.today'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'file_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.FileType']"}),
+ 'general_contractor': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'file_responsability'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'internal_reference': ('django.db.models.fields.CharField', [], {'max_length': '60', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'numeric_reference': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'permit_reference': ('django.db.models.fields.CharField', [], {'max_length': '60', 'null': 'True', 'blank': 'True'}),
+ 'permit_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.PermitType']", 'null': 'True', 'blank': 'True'}),
+ 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'reception_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'reference_number': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'related_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.File']", 'null': 'True', 'blank': 'True'}),
+ 'responsible_town_planning_service': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'saisine_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_files.SaisineType']", 'null': 'True', 'blank': 'True'}),
+ 'total_developed_surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'total_surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'towns': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'file'", 'symmetrical': 'False', 'to': "orm['ishtar_common.Town']"}),
+ 'year': ('django.db.models.fields.IntegerField', [], {'default': '2013'})
+ },
+ 'archaeological_files.filetype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'FileType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'})
+ },
+ 'archaeological_files.permittype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'PermitType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'})
+ },
+ 'archaeological_files.saisinetype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'SaisineType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'delay': ('django.db.models.fields.IntegerField', [], {}),
+ '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'})
+ },
+ 'archaeological_operations.acttype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'ActType'},
+ 'associated_template': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'acttypes'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['ishtar_common.DocumentTemplate']"}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'intented_to': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'archaeological_operations.administrativeact': {
+ 'Meta': {'object_name': 'AdministrativeAct'},
+ 'act_object': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'act_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.ActType']"}),
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'administrative_act'", 'null': 'True', 'to': "orm['archaeological_files.File']"}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'operation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'administrative_act'", 'null': 'True', 'to': "orm['archaeological_operations.Operation']"}),
+ 'operator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Organization']", 'null': 'True', 'blank': 'True'}),
+ 'ref_sra': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'scientific': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'signatory': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'signature_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'archaeological_operations.archaeologicalsite': {
+ 'Meta': {'object_name': 'ArchaeologicalSite'},
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'reference': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'})
+ },
+ 'archaeological_operations.historicaladministrativeact': {
+ 'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalAdministrativeAct'},
+ 'act_object': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'act_type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'associated_file_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'}),
+ 'in_charge_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'operation_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'operator_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'ref_sra': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'scientific_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'signatory_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'signature_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'archaeological_operations.historicaloperation': {
+ 'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalOperation'},
+ 'associated_file_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'cached_label': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
+ 'cira_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'cira_rapporteur_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'code_dracar': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'code_patriarche': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'common_name': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
+ 'cost': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'eas_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'effective_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'excavation_end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'fnap_cost': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'fnap_financing': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'geoarchaeological_context_prescription': ('django.db.models.fields.NullBooleanField', [], {'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'}),
+ 'in_charge_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'large_area_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'negative_result': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'operation_code': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'operation_type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'operator_reference': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'optional_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'report_delivery_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'scheduled_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'zoning_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'archaeological_operations.operation': {
+ 'Meta': {'object_name': 'Operation'},
+ 'archaeological_sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['archaeological_operations.ArchaeologicalSite']", 'symmetrical': 'False'}),
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'operations'", 'null': 'True', 'to': "orm['archaeological_files.File']"}),
+ 'cached_label': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}),
+ 'cira_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'cira_rapporteur': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'code_dracar': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+ 'code_patriarche': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'common_name': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
+ 'cost': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'eas_number': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'effective_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'excavation_end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'fnap_cost': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'fnap_financing': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+ 'geoarchaeological_context_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'in_charge': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'operation_responsability'", 'null': 'True', 'to': "orm['ishtar_common.Person']"}),
+ 'large_area_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'negative_result': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'operation_code': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'operation_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['archaeological_operations.OperationType']"}),
+ 'operator_reference': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'optional_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'periods': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['archaeological_operations.Period']", 'symmetrical': 'False'}),
+ 'remains': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['archaeological_operations.RemainType']", 'symmetrical': 'False'}),
+ 'report_delivery_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'scheduled_man_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'towns': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ishtar_common.Town']", 'symmetrical': 'False'}),
+ 'year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'zoning_prescription': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'archaeological_operations.operationbydepartment': {
+ 'Meta': {'object_name': 'OperationByDepartment', 'db_table': "'operation_department'", 'managed': 'False'},
+ 'department': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'operation': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.Operation']"})
+ },
+ 'archaeological_operations.operationsource': {
+ 'Meta': {'object_name': 'OperationSource'},
+ 'associated_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'authors': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'operationsource_related'", 'symmetrical': 'False', 'to': "orm['ishtar_common.Author']"}),
+ 'creation_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'index': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'internal_reference': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
+ 'operation': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'source'", 'to': "orm['archaeological_operations.Operation']"}),
+ 'receipt_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'reference': ('django.db.models.fields.CharField', [], {'max_length': '25', 'null': 'True', 'blank': 'True'}),
+ 'source_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.SourceType']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'})
+ },
+ 'archaeological_operations.operationtype': {
+ 'Meta': {'ordering': "['label']", 'object_name': 'OperationType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'}),
+ 'preventive': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'archaeological_operations.parcel': {
+ 'Meta': {'object_name': 'Parcel'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'parcels'", 'null': 'True', 'to': "orm['archaeological_files.File']"}),
+ 'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'operation': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'parcels'", 'null': 'True', 'to': "orm['archaeological_operations.Operation']"}),
+ 'parcel_number': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'section': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'town': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'parcels'", 'to': "orm['ishtar_common.Town']"}),
+ 'year': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'archaeological_operations.parcelowner': {
+ 'Meta': {'object_name': 'ParcelOwner'},
+ 'end_date': ('django.db.models.fields.DateField', [], {}),
+ 'history_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Person']"}),
+ 'parcel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.Parcel']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {})
+ },
+ 'archaeological_operations.period': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'Period'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archaeological_operations.Period']", 'null': 'True', 'blank': 'True'}),
+ 'start_date': ('django.db.models.fields.IntegerField', [], {}),
+ 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'archaeological_operations.remaintype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'RemainType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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'})
+ },
+ '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': 'False'}),
+ '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']", '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.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'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': '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': '30', 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.organizationtype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'OrganizationType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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', 'to': "orm['ishtar_common.Organization']"}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
+ 'email': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
+ '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'}),
+ 'surname': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
+ 'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'})
+ },
+ 'ishtar_common.persontype': {
+ 'Meta': {'ordering': "('label',)", 'object_name': 'PersonType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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.sourcetype': {
+ 'Meta': {'object_name': 'SourceType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ '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.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 = ['archaeological_operations'] \ No newline at end of file
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index 814924a01..9edbb382c 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -48,7 +48,7 @@ class OperationType(GeneralType):
def is_preventive(cls, ope_type_id, key=''):
try:
op_type = OperationType.objects.get(pk=ope_type_id)
- except ObjectDoesNotExist:
+ except OperationType.DoesNotExist:
return False
if not key:
return op_type.preventive
@@ -76,7 +76,7 @@ class Period(GeneralType) :
return self.label
class ArchaeologicalSite(BaseHistorizedItem):
- reference = models.CharField(_(u"Reference"), max_length=20)
+ reference = models.CharField(_(u"Reference"), max_length=20, unique=True)
name = models.CharField(_(u"Name"), max_length=200,
null=True, blank=True)
class Meta:
@@ -95,6 +95,12 @@ class ArchaeologicalSite(BaseHistorizedItem):
ugettext(u"Can delete own Archaeological site")),
)
+ def __unicode__(self):
+ name = self.reference
+ if self.name:
+ name += u" %s %s" % (settings.JOINT, self.name)
+ return name
+
class Operation(BaseHistorizedItem, OwnPerms):
TABLE_COLS = ['year_index', 'operation_type', 'remains', 'towns',
'associated_file_short_label', 'start_date',
@@ -238,8 +244,6 @@ class Operation(BaseHistorizedItem, OwnPerms):
def find_docs_q(self):
from archaeological_finds.models import FindSource
- print FindSource.objects.filter(
- find__base_finds__context_record__operation=self).query
return FindSource.objects.filter(
find__base_finds__context_record__operation=self)
diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py
index 5efc61dab..e6a561f02 100644
--- a/archaeological_operations/urls.py
+++ b/archaeological_operations/urls.py
@@ -78,6 +78,11 @@ urlpatterns += patterns('archaeological_operations.views',
'get_operationsource', name='get-operationsource'),
url(r'dashboard_operation/$', 'dashboard_operation',
name='dashboard-operation'),
+ url(r'autocomplete-archaeologicalsite/$',
+ 'autocomplete_archaeologicalsite',
+ name='autocomplete-archaeologicalsite'),
+ url(r'new-archaeologicalsite/(?P<parent_name>.+)?/$',
+ 'new_archaeologicalsite', name='new-archaeologicalsite'),
url(r'autocomplete-patriarche/$', 'autocomplete_patriarche',
name='autocomplete-patriarche'),
url(r'operation_administrativeact_document/$',
diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py
index d6e97b1d9..f48c55f57 100644
--- a/archaeological_operations/views.py
+++ b/archaeological_operations/views.py
@@ -26,7 +26,7 @@ from django.shortcuts import render_to_response
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
-from ishtar_common.views import get_item, show_item, revert_item
+from ishtar_common.views import get_item, show_item, revert_item, new_item
from ishtar_common.wizards import SearchWizard
from wizards import *
from forms import *
@@ -54,6 +54,32 @@ def autocomplete_patriarche(request, non_closed=True):
for operation in operations])
return HttpResponse(data, mimetype='text/plain')
+def autocomplete_archaeologicalsite(request):
+ if (not request.user.has_perm(
+ 'archaeological_operations.view_archaeologicalsite',
+ models.ArchaeologicalSite)
+ and not request.user.has_perm(
+ 'archaeological_operations.view_own_archaeologicalsite',
+ models.ArchaeologicalSite)):
+ return HttpResponse(mimetype='text/plain')
+ if not request.GET.get('term'):
+ return HttpResponse(mimetype='text/plain')
+ q = request.GET.get('term')
+ query = Q()
+ for q in q.split(' '):
+ qt = Q(reference__icontains=q) | Q(name__icontains=q)
+ query = query & qt
+ limit = 15
+ sites = models.ArchaeologicalSite.objects.filter(query
+ ).order_by('reference')[:limit]
+ data = json.dumps([{'id':site.pk,
+ 'value':unicode(site)[:60]}
+ for site in sites])
+ return HttpResponse(data, mimetype='text/plain')
+
+new_archaeologicalsite = new_item(models.ArchaeologicalSite,
+ ArchaeologicalSiteForm)
+
def autocomplete_operation(request, non_closed=True):
person_types = request.user.ishtaruser.person.person_type
if (not request.user.has_perm('ishtar_common.view_operation',
diff --git a/ishtar_common/templates/blocks/JQueryAutocomplete.js b/ishtar_common/templates/blocks/JQueryAutocomplete.js
new file mode 100644
index 000000000..eb365c38a
--- /dev/null
+++ b/ishtar_common/templates/blocks/JQueryAutocomplete.js
@@ -0,0 +1,19 @@
+$("#id_select_{{field_id}}").autocomplete({
+ source: {{source}},
+ select: function( event, ui ) {
+ if(ui.item){
+ $('#id_{{field_id}}').val(ui.item.id);
+ } else {
+ $('#id_{{field_id}}').val(null);
+ }
+ },
+ minLength: 2{% if options %},
+ {{options}}
+ {% endif %}
+});
+
+$('#id_select_{{field_id}}').live('click', function(){
+ $('#id_{{field_id}}').val(null);
+ $('#id_select_{{field_id}}').val(null);
+});
+
diff --git a/ishtar_common/templates/blocks/JQueryAutocompleteMultiple.js b/ishtar_common/templates/blocks/JQueryAutocompleteMultiple.js
new file mode 100644
index 000000000..56133ef4e
--- /dev/null
+++ b/ishtar_common/templates/blocks/JQueryAutocompleteMultiple.js
@@ -0,0 +1,92 @@
+{% load replace_underscore %}
+function split( val ) {
+ return val.split( /,\s*/ );
+}
+
+function extractLast( term ) {
+ return split( term ).pop();
+}
+
+var {{field_id|replace_underscore}}_values = $('#id_{{field_id}}').val().split(',');
+if(!{{field_id|replace_underscore}}_values){
+ {{field_id|replace_underscore}}_values = new Array();
+}
+var {{field_id|replace_underscore}}_ctext = "";
+
+$("#id_select_{{field_id}}")
+ // don't navigate away from the field on tab when selecting an item
+ .bind( "keydown", function( event ) {
+ if ( event.keyCode === $.ui.keyCode.TAB &&
+ $( this ).data( "ui-autocomplete" ).menu.active ) {
+ event.preventDefault();
+ } else if (event.keyCode === $.ui.keyCode.DELETE ||
+ event.keyCode === $.ui.keyCode.BACKSPACE){
+ {{field_id|replace_underscore}}_ctext =
+ $("#id_select_{{field_id}}").val().split(',');
+ }
+ })
+ .bind( "keyup", function( event ) {
+ if (event.keyCode === $.ui.keyCode.DELETE ||
+ event.keyCode === $.ui.keyCode.BACKSPACE){
+ var new_val = $("#id_select_{{field_id}}").val().split(',');
+ var length = {{field_id|replace_underscore}}_ctext.length;
+ for (idx=0;idx<length;idx++){
+ if(idx >= new_val.length ||
+ {{field_id|replace_underscore}}_ctext[idx] != new_val[idx]){
+ if (idx == (length - 1) && length > 1){
+ if ({{field_id|replace_underscore}}_ctext[idx].trim() == ""){
+ idx = idx - 1;
+ } else {
+ return;
+ }
+ }
+ {{field_id|replace_underscore}}_ctext.splice(idx, 1);
+ // remove value
+ if (idx < {{field_id|replace_underscore}}_values.length){
+ {{field_id|replace_underscore}}_values.splice(idx, 1);
+ $('#id_{{field_id}}').val({{field_id|replace_underscore}}_values);
+ }
+ if ({{field_id|replace_underscore}}_ctext.length > 0 &&
+ {{field_id|replace_underscore}}_ctext[0].length){
+ // remove leading space
+ if ({{field_id|replace_underscore}}_ctext[0][0] == ' '){
+ {{field_id|replace_underscore}}_ctext[0] =
+ {{field_id|replace_underscore}}_ctext[0].trim();
+ }
+ // remove trailing space
+ var last = {{field_id|replace_underscore}}_ctext.length -1;
+ {{field_id|replace_underscore}}_ctext[last] =
+ {{field_id|replace_underscore}}_ctext[last].trim();
+ }
+ this.value = {{field_id|replace_underscore}}_ctext.join(", ");
+ return
+ }
+ }
+ }
+ }).autocomplete({
+ source: function( request, response ) {
+ $.getJSON({{source}}, {
+ term: extractLast( request.term )
+ }, response );
+ },
+ focus: function() {
+ // prevent value inserted on focus
+ return false;
+ },
+ select: function( event, ui ) {
+ var terms = split( this.value );
+ // remove the current input
+ terms.pop();
+ // add the selected item
+ terms.push( ui.item.value );
+ {{field_id|replace_underscore}}_values.push(ui.item.id);
+ // add placeholder to get the comma-and-space at the end
+ $('#id_{{field_id}}').val({{field_id|replace_underscore}}_values);
+ terms.push( "" );
+ this.value = terms.join( ", " );
+ return false;
+ },
+ minLength: 2{% if options %},
+ {{options}}
+ {% endif %}
+});
diff --git a/ishtar_common/templatetags/replace_underscore.py b/ishtar_common/templatetags/replace_underscore.py
new file mode 100644
index 000000000..66931e6fe
--- /dev/null
+++ b/ishtar_common/templatetags/replace_underscore.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from django.template import Library
+
+register = Library()
+
+@register.filter
+def replace_underscore(value):
+ return value.replace('-', '_')
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index a97cfe70b..fc3ada283 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -27,6 +27,7 @@ from django.forms import ClearableFileInput
from django.forms.widgets import flatatt
from django.template import Context, loader
from django.utils.encoding import smart_unicode
+from django.utils.functional import lazy
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.simplejson import JSONEncoder
@@ -34,6 +35,44 @@ from django.utils.translation import ugettext_lazy as _
import models
+reverse_lazy = lazy(reverse, unicode)
+
+class MultipleAutocompleteField(forms.MultipleChoiceField):
+ def __init__(self, *args, **kwargs):
+ model = None
+ if 'model' in kwargs:
+ model = kwargs.pop('model')
+ if 'choices' not in kwargs and model:
+ kwargs['choices'] = [(i.pk, unicode(i))for i in model.objects.all()]
+ new = kwargs.pop('new') if 'new' in kwargs else None
+ if 'widget' not in kwargs and model:
+ kwargs['widget'] = JQueryAutoComplete(reverse_lazy(
+ 'autocomplete-'+model.__name__.lower()),
+ associated_model=model, new=new,
+ multiple=True)
+ super(MultipleAutocompleteField, self).__init__(*args, **kwargs)
+
+ def clean(self, value):
+ if value:
+ # clean JS messup with values
+ try:
+ if type(value) not in (list, tuple):
+ value = [value]
+ else:
+ val = value
+ value = []
+ for v in val:
+ v = unicode(v).strip('[').strip(']'
+ ).strip('u').strip("'").strip('"')
+ value += [int(v.strip())
+ for v in list(set(v.split(',')))
+ if v.strip()]
+ except (TypeError, ValueError):
+ value = []
+ else:
+ value = []
+ return super(MultipleAutocompleteField, self).clean(value)
+
class DeleteWidget(forms.CheckboxInput):
def render(self, name, value, attrs=None):
final_attrs = flatatt(self.build_attrs(attrs, name=name,
@@ -95,7 +134,7 @@ class JQueryDate(forms.TextInput):
class JQueryAutoComplete(forms.TextInput):
def __init__(self, source, associated_model=None, options={}, attrs={},
- new=False):
+ new=False, multiple=False):
"""
Source can be a list containing the autocomplete values or a
string containing the url used for the request.
@@ -108,6 +147,13 @@ class JQueryAutoComplete(forms.TextInput):
self.options = JSONEncoder().encode(options)
self.attrs.update(attrs)
self.new = new
+ self.multiple = multiple
+
+ def value_from_datadict(self, data, files, name):
+ if self.multiple:
+ return data.getlist(name, None)
+ else:
+ return data.get(name, None)
def render_js(self, field_id):
if isinstance(self.source, list):
@@ -119,39 +165,54 @@ class JQueryAutoComplete(forms.TextInput):
source = "'" + unicode(self.source) + "'"
except:
raise ValueError('source type is not valid')
- options = 'source : ' + source
- options += ''', select: function( event, ui ) {
- if(ui.item){
- $('#id_%s').val(ui.item.id);
- } else {
- $('#id_%s').val(null);
- }
- }, minLength: 2
- ''' % (field_id, field_id)
+ dct = {'source':mark_safe(source),
+ 'field_id':field_id}
if self.options:
- options += ',%s' % self.options
+ dct['options'] = mark_safe('%s' % self.options)
- js = u'$(\'#id_select_%s\').autocomplete({%s});\n' % (field_id, options)
- js += u'''$(\'#id_select_%s\').live('click', function(){
- $('#id_%s').val(null);
- $('#id_select_%s').val(null);
-});''' % (field_id, field_id, field_id)
+ js = ""
+ tpl = 'blocks/JQueryAutocomplete.js'
+ if self.multiple:
+ tpl = 'blocks/JQueryAutocompleteMultiple.js'
+ t = loader.get_template(tpl)
+ js = t.render(Context(dct))
return js
def render(self, name, value=None, attrs=None):
attrs_hidden = self.build_attrs(attrs, name=name)
attrs_select = self.build_attrs(attrs)
-
if value:
- val = escape(smart_unicode(value))
- attrs_hidden['value'] = val
- attrs_select['value'] = val
- if self.associated_model:
- try:
- attrs_select['value'] = unicode(
- self.associated_model.objects.get(pk=value))
- except:
- attrs_select['value'] = ""
+ hiddens = []
+ selects = []
+ values = value
+ if type(value) not in (list, tuple):
+ values = unicode(escape(smart_unicode(value)))
+ values = values.replace('[', '').replace(']', '')
+ values = values.split(',')
+ else:
+ values = []
+ for v in value:
+ values += v.split(',')
+ for v in values:
+ if not v:
+ continue
+ hiddens.append(v)
+ selects.append(v)
+ if self.associated_model:
+ try:
+ selects[-1] = unicode(
+ self.associated_model.objects.get(pk=v))
+ except (self.associated_model.DoesNotExist, ValueError):
+ selects.pop()
+ hiddens.pop()
+ if self.multiple:
+ attrs_hidden['value'] = ", ".join(hiddens)
+ if selects:
+ selects.append("")
+ attrs_select['value'] = ", ".join(selects)
+ else:
+ attrs_hidden['value'] = hiddens[0]
+ attrs_select['value'] = selects[0]
if not self.attrs.has_key('id'):
attrs_hidden['id'] = 'id_%s' % name
attrs_select['id'] = 'id_select_%s' % name
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index 55c9d0d9d..a237fb327 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -24,12 +24,22 @@ from django.contrib.formtools.wizard.views import NamedUrlWizardView
from django.core.exceptions import ObjectDoesNotExist
from django.core.files.images import ImageFile
from django.db.models.fields.files import FileField
+from django.db.models.fields.related import ManyToManyField
from django.shortcuts import render_to_response
from django.template import RequestContext
-from django.utils.datastructures import MultiValueDict
+from django.utils.datastructures import MultiValueDict as BaseMultiValueDict
from django.utils.translation import ugettext_lazy as _
import models
+class MultiValueDict(BaseMultiValueDict):
+ def get(self, *args, **kwargs):
+ v = super(MultiValueDict, self).getlist(*args, **kwargs)
+ if len(v) > 1:
+ v = ",".join(v)
+ else:
+ v = super(MultiValueDict, self).get(*args, **kwargs)
+ return v
+
class Wizard(NamedUrlWizardView):
model = None
label = ''
@@ -211,7 +221,8 @@ class Wizard(NamedUrlWizardView):
if type(value) in (tuple, list):
values = value
elif "," in unicode(value):
- values = unicode(value).split(",")
+ values = unicode(value
+ ).strip('[').strip(']').split(",")
else:
values = [value]
rendered_values = []
@@ -344,6 +355,12 @@ class Wizard(NamedUrlWizardView):
isinstance(obj.__class__._meta.get_field(k), ImageFile)):
if not dct[k]:
dct[k] = None
+ if isinstance(obj.__class__._meta.get_field(k),
+ ManyToManyField):
+ if not dct[k]:
+ dct[k] = []
+ elif type(dct[k]) not in (list, tuple):
+ dct[k] = [dct[k]]
setattr(obj, k, dct[k])
try:
obj.full_clean()
@@ -516,7 +533,8 @@ class Wizard(NamedUrlWizardView):
elif hasattr(form, 'extra_form') and hasattr(form.extra_form, 'fields')\
and form.extra_form.fields.keys():
frm = form.extra_form
- elif hasattr(form, 'forms') and form.forms and form.forms[0].fields.keys():
+ elif hasattr(form, 'forms') and form.forms \
+ and form.forms[0].fields.keys():
frm = form.forms[0]
if frm:
first_field = frm.fields[frm.fields.keyOrder[0]]
@@ -675,6 +693,12 @@ class Wizard(NamedUrlWizardView):
value = obj
break
value = getattr(value, field)
+ if hasattr(value, 'all') and callable(value.all):
+ if not value.count():
+ continue
+ initial.setlist(base_field,
+ [unicode(v.pk) for v in value.all()])
+ continue
if value == obj:
continue
if hasattr(value, 'pk'):