summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/forms.py4
-rw-r--r--ishtar_common/locale/django.pot126
-rw-r--r--ishtar_common/models.py13
-rw-r--r--ishtar_common/templates/ishtar/wizard/confirm_wizard.html4
-rw-r--r--ishtar_common/templates/ishtar/wizard/default_wizard.html7
-rw-r--r--ishtar_common/templatetags/window_tables.py12
-rw-r--r--ishtar_common/tests.py31
-rw-r--r--ishtar_common/views.py35
-rw-r--r--ishtar_common/widgets.py47
-rw-r--r--ishtar_common/wizards.py63
10 files changed, 236 insertions, 106 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py
index 043b03f61..42d74f9ef 100644
--- a/ishtar_common/forms.py
+++ b/ishtar_common/forms.py
@@ -33,6 +33,7 @@ from django.utils.translation import ugettext_lazy as _
import models
import widgets
+from wizards import MultiValueDict
# from formwizard.forms import NamedUrlSessionFormWizard
@@ -224,7 +225,6 @@ class ManageOldType(object):
if prefix not in k:
continue
new_k = k[len(prefix) + 1:]
- items = []
if hasattr(kwargs['data'], 'getlist'):
items = kwargs['data'].getlist(k)
else:
@@ -238,7 +238,6 @@ class ManageOldType(object):
if 'initial' in kwargs and kwargs['initial']:
for k in kwargs['initial']:
if k not in self.init_data or not self.init_data[k]:
- items = []
if hasattr(kwargs['initial'], 'getlist'):
items = kwargs['initial'].getlist(k)
else:
@@ -249,6 +248,7 @@ class ManageOldType(object):
if k not in self.init_data:
self.init_data[k] = []
self.init_data[k].append(val)
+ self.init_data = MultiValueDict(self.init_data)
super(ManageOldType, self).__init__(*args, **kwargs)
diff --git a/ishtar_common/locale/django.pot b/ishtar_common/locale/django.pot
index e08650308..813f31a3c 100644
--- a/ishtar_common/locale/django.pot
+++ b/ishtar_common/locale/django.pot
@@ -160,7 +160,7 @@ msgid "Template"
msgstr ""
#: forms_common.py:41 forms_common.py:59 forms_common.py:182
-#: forms_common.py:406 models.py:1426 models.py:2819
+#: forms_common.py:406 models.py:1426 models.py:2818
#: templates/blocks/JQueryAdvancedTown.html:19
#: templates/ishtar/sheet_organization.html:13
msgid "Town"
@@ -177,7 +177,7 @@ msgid ""
msgstr ""
#: forms_common.py:68 forms_common.py:855 ishtar_menu.py:47 models.py:1599
-#: models.py:2445 models.py:2627 models.py:2689
+#: models.py:2445 models.py:2627 models.py:2688
#: templates/ishtar/sheet_person.html:4
msgid "Person"
msgstr ""
@@ -196,7 +196,7 @@ msgstr ""
#: forms_common.py:173 forms_common.py:210 forms_common.py:322
#: forms_common.py:376 forms_common.py:446 models.py:1027 models.py:1359
-#: models.py:1645 models.py:1864 models.py:2325 models.py:2431 models.py:2805
+#: models.py:1645 models.py:1864 models.py:2325 models.py:2431 models.py:2804
#: templates/ishtar/sheet_organization.html:8
#: templates/ishtar/sheet_organization.html:21
msgid "Name"
@@ -245,7 +245,7 @@ msgid "Mobile phone"
msgstr ""
#: forms_common.py:211 forms_common.py:325 forms_common.py:449 models.py:2025
-#: models.py:2327 models.py:2740 templates/sheet_ope.html:85
+#: models.py:2327 models.py:2739 templates/sheet_ope.html:85
#: templates/sheet_ope.html.py:105 templates/sheet_ope.html:126
#: templates/ishtar/import_list.html:13
#: templates/ishtar/sheet_organization.html:23
@@ -288,7 +288,7 @@ msgid "Identity"
msgstr ""
#: forms_common.py:371 forms_common.py:773 forms_common.py:822 models.py:1996
-#: models.py:2423 models.py:2425 models.py:2737 templates/sheet_ope.html:104
+#: models.py:2423 models.py:2425 models.py:2736 templates/sheet_ope.html:104
#: templates/ishtar/blocks/window_tables/documents.html:7
msgid "Title"
msgstr ""
@@ -365,7 +365,7 @@ msgstr ""
msgid "Account"
msgstr ""
-#: forms_common.py:575 wizards.py:1194
+#: forms_common.py:575 wizards.py:1217
msgid "New password"
msgstr ""
@@ -389,7 +389,7 @@ msgstr ""
msgid "Send the new password by email?"
msgstr ""
-#: forms_common.py:628 forms_common.py:641 models.py:2820
+#: forms_common.py:628 forms_common.py:641 models.py:2819
msgid "Towns"
msgstr ""
@@ -405,7 +405,7 @@ msgstr ""
msgid "Documentation informations"
msgstr ""
-#: forms_common.py:775 forms_common.py:823 models.py:1997 models.py:2714
+#: forms_common.py:775 forms_common.py:823 models.py:1997 models.py:2713
msgid "Source type"
msgstr ""
@@ -417,37 +417,37 @@ msgstr ""
msgid "Internal reference"
msgstr ""
-#: forms_common.py:783 models.py:2751
+#: forms_common.py:783 models.py:2750
msgid "Numerical ressource (web address)"
msgstr ""
-#: forms_common.py:784 models.py:2753
+#: forms_common.py:784 models.py:2752
msgid "Receipt date"
msgstr ""
-#: forms_common.py:786 models.py:2154 models.py:2755
+#: forms_common.py:786 models.py:2154 models.py:2754
msgid "Creation date"
msgstr ""
-#: forms_common.py:789 models.py:2758
+#: forms_common.py:789 models.py:2757
msgid "Receipt date in documentation"
msgstr ""
#: forms_common.py:791 forms_common.py:827 models.py:322 models.py:627
-#: models.py:1891 models.py:2437 models.py:2765
+#: models.py:1891 models.py:2437 models.py:2764
msgid "Comment"
msgstr ""
#: forms_common.py:793 forms_common.py:826 models.py:1029 models.py:1649
-#: models.py:1823 models.py:1865 models.py:2764 templates/sheet_ope.html:128
+#: models.py:1823 models.py:1865 models.py:2763 templates/sheet_ope.html:128
msgid "Description"
msgstr ""
-#: forms_common.py:796 models.py:2766
+#: forms_common.py:796 models.py:2765
msgid "Additional information"
msgstr ""
-#: forms_common.py:798 forms_common.py:830 models.py:2768
+#: forms_common.py:798 forms_common.py:830 models.py:2767
msgid "Has a duplicate"
msgstr ""
@@ -462,7 +462,7 @@ msgid ""
"p>"
msgstr ""
-#: forms_common.py:819 forms_common.py:848 forms_common.py:882 models.py:2694
+#: forms_common.py:819 forms_common.py:848 forms_common.py:882 models.py:2693
#: templates/ishtar/wizard/wizard_person_deletion.html:124
msgid "Author"
msgstr ""
@@ -475,7 +475,7 @@ msgstr ""
msgid "Would you like to delete this documentation?"
msgstr ""
-#: forms_common.py:856 models.py:1998 models.py:2682 models.py:2691
+#: forms_common.py:856 models.py:1998 models.py:2681 models.py:2690
msgid "Author type"
msgstr ""
@@ -487,7 +487,7 @@ msgstr ""
msgid "There are identical authors."
msgstr ""
-#: forms_common.py:893 models.py:2695 models.py:2747
+#: forms_common.py:893 models.py:2694 models.py:2746
#: templates/sheet_ope.html:106
#: templates/ishtar/blocks/window_tables/documents.html:9
msgid "Authors"
@@ -505,7 +505,7 @@ msgstr ""
msgid "Deletion"
msgstr ""
-#: ishtar_menu.py:39 models.py:1155 views.py:1501
+#: ishtar_menu.py:39 models.py:1155 views.py:1513
msgid "Global variables"
msgstr ""
@@ -537,11 +537,11 @@ msgstr ""
msgid "Imports"
msgstr ""
-#: ishtar_menu.py:112 views.py:1509
+#: ishtar_menu.py:112 views.py:1521
msgid "New import"
msgstr ""
-#: ishtar_menu.py:116 views.py:1523
+#: ishtar_menu.py:116 views.py:1535
msgid "Current imports"
msgstr ""
@@ -589,7 +589,7 @@ msgstr ""
msgid "Creator"
msgstr ""
-#: models.py:891 models.py:2831
+#: models.py:891 models.py:2830
msgid "Order"
msgstr ""
@@ -834,11 +834,11 @@ msgstr ""
msgid "Operation source"
msgstr ""
-#: models.py:1609 views.py:1317 views.py:1367
+#: models.py:1609 views.py:1329 views.py:1379
msgid "Archaeological files"
msgstr ""
-#: models.py:1611 views.py:1320 views.py:1375
+#: models.py:1611 views.py:1332 views.py:1387
msgid "Context records"
msgstr ""
@@ -970,11 +970,11 @@ msgstr ""
msgid "Importer - Targets keys"
msgstr ""
-#: models.py:1999 models.py:2730 models.py:2743
+#: models.py:1999 models.py:2729 models.py:2742
msgid "Format"
msgstr ""
-#: models.py:2000 models.py:2835
+#: models.py:2000 models.py:2834
msgid "Operation type"
msgstr ""
@@ -1022,7 +1022,7 @@ msgstr ""
msgid "Context record relation type"
msgstr ""
-#: models.py:2015 models.py:2722
+#: models.py:2015 models.py:2721
msgid "Support type"
msgstr ""
@@ -1300,71 +1300,71 @@ msgstr ""
msgid "Ishtar users"
msgstr ""
-#: models.py:2677
+#: models.py:2676
msgid "To modify the password use the form in Auth > User"
msgstr ""
-#: models.py:2683
+#: models.py:2682
msgid "Author types"
msgstr ""
-#: models.py:2715
+#: models.py:2714
msgid "Source types"
msgstr ""
-#: models.py:2723
+#: models.py:2722
msgid "Support types"
msgstr ""
-#: models.py:2731
+#: models.py:2730
msgid "Formats"
msgstr ""
-#: models.py:2738
+#: models.py:2737
msgid "External ID"
msgstr ""
-#: models.py:2741
+#: models.py:2740
msgid "Support"
msgstr ""
-#: models.py:2745
+#: models.py:2744
msgid "Scale"
msgstr ""
-#: models.py:2759
+#: models.py:2758
msgid "Item number"
msgstr ""
-#: models.py:2760
+#: models.py:2759
msgid "Ref."
msgstr ""
-#: models.py:2763
+#: models.py:2762
msgid "Internal ref."
msgstr ""
-#: models.py:2806
+#: models.py:2805
msgid "Surface (m2)"
msgstr ""
-#: models.py:2807 templates/sheet_ope.html:46 templates/sheet_ope.html.py:107
+#: models.py:2806 templates/sheet_ope.html:46 templates/sheet_ope.html.py:107
msgid "Localisation"
msgstr ""
-#: models.py:2832
+#: models.py:2831
msgid "Is preventive"
msgstr ""
-#: models.py:2836
+#: models.py:2835
msgid "Operation types"
msgstr ""
-#: models.py:2865
+#: models.py:2864
msgid "Preventive"
msgstr ""
-#: models.py:2866
+#: models.py:2865
msgid "Research"
msgstr ""
@@ -1420,76 +1420,76 @@ msgstr ""
msgid "Find"
msgstr ""
-#: views.py:1256 views.py:1299
+#: views.py:1268 views.py:1311
msgid "Operation not permitted."
msgstr ""
-#: views.py:1258
+#: views.py:1270
#, python-format
msgid "New %s"
msgstr ""
-#: views.py:1318 views.py:1371
+#: views.py:1330 views.py:1383
msgid "Operations"
msgstr ""
-#: views.py:1322 views.py:1378
+#: views.py:1334 views.py:1390
msgid "Finds"
msgstr ""
-#: views.py:1570 templates/ishtar/import_list.html:43
+#: views.py:1582 templates/ishtar/import_list.html:43
msgid "Link unmatched items"
msgstr ""
-#: views.py:1585
+#: views.py:1597
msgid "Delete import"
msgstr ""
-#: views.py:1624
+#: views.py:1636
msgid "Merge persons"
msgstr ""
-#: views.py:1648
+#: views.py:1660
msgid "Select the main person"
msgstr ""
-#: views.py:1657
+#: views.py:1669
msgid "Merge organization"
msgstr ""
-#: views.py:1667
+#: views.py:1679
msgid "Select the main organization"
msgstr ""
-#: views.py:1707 views.py:1723
+#: views.py:1719 views.py:1735
msgid "Corporation manager"
msgstr ""
-#: widgets.py:239 widgets.py:347 widgets.py:462
+#: widgets.py:239 widgets.py:346 widgets.py:461
msgid "Search..."
msgstr ""
-#: widgets.py:642 templatetags/window_tables.py:79
+#: widgets.py:643 templatetags/window_tables.py:81
msgid "No results"
msgstr ""
-#: widgets.py:643 templatetags/window_tables.py:80
+#: widgets.py:644 templatetags/window_tables.py:82
msgid "Loading..."
msgstr ""
-#: widgets.py:644
+#: widgets.py:645
msgid "Remove"
msgstr ""
-#: wizards.py:323 templates/ishtar/import_delete.html:20
+#: wizards.py:335 templates/ishtar/import_delete.html:20
msgid "Yes"
msgstr ""
-#: wizards.py:325
+#: wizards.py:337
msgid "No"
msgstr ""
-#: wizards.py:1251
+#: wizards.py:1274
#, python-format
msgid "[%(app_name)s] Account creation/modification"
msgstr ""
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 5b822c7dd..d4f0c595e 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -413,10 +413,12 @@ class GeneralType(Cached, models.Model):
new_vals = []
if not initial:
return []
+ if type(initial) not in (list, tuple):
+ initial = [initial]
for value in initial:
try:
pk = int(value)
- except ValueError:
+ except (ValueError, TypeError):
continue
if pk in type_pks:
continue
@@ -447,6 +449,7 @@ class GeneralType(Cached, models.Model):
keys = ['__get_types']
keys += [u"{}".format(ex) for ex in exclude] + [
empty_first and 'empty_first' or ''] + [u"{}".format(default)]
+ keys += [u'{}-{}'.format(unicode(k), dct[k]) for k in dct]
cache_key, value = get_cache(cls, keys)
if value and not force:
return value
@@ -485,7 +488,10 @@ class GeneralType(Cached, models.Model):
pass
items = cls.objects.filter(**dct)
if default and default != "None":
- exclude.append(default.txt_idx)
+ if hasattr(default, 'txt_idx'):
+ exclude.append(default.txt_idx)
+ else:
+ exclude.append(default)
if exclude:
items = items.exclude(txt_idx__in=exclude)
for item in items.order_by(*cls._meta.ordering).all():
@@ -664,7 +670,7 @@ class ImageModel(models.Model):
null=True, max_length=255)
IMAGE_MAX_SIZE = settings.IMAGE_MAX_SIZE
THUMB_MAX_SIZE = settings.THUMB_MAX_SIZE
- IMAGE_PREFIX = '/'
+ IMAGE_PREFIX = ''
class Meta:
abstract = True
@@ -2639,7 +2645,6 @@ class IshtarUser(User):
surname = user.first_name or default
name = user.last_name or default
email = user.email
- person_type = None
if user.is_superuser:
ADMINISTRATOR, created = PersonType.objects.get_or_create(
txt_idx='administrator')
diff --git a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html
index 9007c867c..1fbaadcd1 100644
--- a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html
+++ b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html
@@ -6,9 +6,9 @@
<form action="." method="post">{% csrf_token %}
<ul id='form_path'>
{% for step in previous_steps %}
- <li><button name="form_prev_step" value="{{forloop.counter0}}">{{step.form_label}}</button></li>
+ <li><button name="form_prev_step" value="{{forloop.counter0}}">{{step}}</button></li>
{% endfor %}
- <li class='current'><a href='#'>{{current_step.form_label}}</a></li>
+ <li class='current'><a href='#'>{{current_step_label}}</a></li>
</ul>
</form>
<form action="." method="post">{% csrf_token %}
diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html
index c52d71536..fad1895bd 100644
--- a/ishtar_common/templates/ishtar/wizard/default_wizard.html
+++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html
@@ -10,11 +10,11 @@
<form action="." method="post">{% csrf_token %}
<ul id='form_path'>
{% for step in previous_steps %}
- <li><button class='change_step' name="form_prev_step" value="{{forloop.counter0}}">{{step.form_label}}</button></li>
+ <li><button class='change_step' name="form_prev_step" value="{{forloop.counter0}}">{{step}}</button></li>
{% endfor %}
- <li class='current'><a href='#'>{{current_step.form_label}}</a></li>
+ <li class='current'><a href='#'>{{current_step_label}}</a></li>
{% for step in next_steps %}
- <li><button class='change_step' name="form_prev_step" value="{{forloop.counter|add:previous_step_counter}}">{{step.form_label}}</button></li>
+ <li><button class='change_step' name="form_prev_step" value="{{forloop.counter|add:previous_step_counter}}">{{step}}</button></li>
{% endfor %}
</ul>
</form>
@@ -24,6 +24,7 @@
<div class='form'>
{{ wizard.form.media }}
{{ wizard.management_form }}
+{% block form_head %}{% endblock %}
{% block form_detail %}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
diff --git a/ishtar_common/templatetags/window_tables.py b/ishtar_common/templatetags/window_tables.py
index acb3d4a0a..377b6e435 100644
--- a/ishtar_common/templatetags/window_tables.py
+++ b/ishtar_common/templatetags/window_tables.py
@@ -17,7 +17,7 @@ from archaeological_operations.models import OperationSource, Operation
from archaeological_context_records.models import ContextRecord, \
ContextRecordSource, RecordRelations as CRRecordRelations
from archaeological_finds.models import Find, FindSource, \
- FindUpstreamTreatments, FindDownstreamTreatments
+ FindUpstreamTreatments, FindDownstreamTreatments, FindTreatments
register = template.Library()
@@ -45,22 +45,28 @@ ASSOCIATED_MODELS['context_records_relations'] = (
ASSOCIATED_MODELS['finds'] = (Find, 'get-find', 'get-find-full')
ASSOCIATED_MODELS['finds_for_ope'] = (
Find, 'get-find-for-ope', 'get-find-full')
+ASSOCIATED_MODELS['finds_for_treatment'] = (
+ Find, 'get-find-for-treatment', 'get-find-full')
ASSOCIATED_MODELS['finds_docs'] = (
FindSource, 'get-findsource', 'get-findsource-full')
ASSOCIATED_MODELS['finds_upstreamtreatments'] = (
FindUpstreamTreatments, 'get-upstreamtreatment', '')
ASSOCIATED_MODELS['finds_downstreamtreatments'] = (
FindDownstreamTreatments, 'get-downstreamtreatment', '')
+ASSOCIATED_MODELS['treatments'] = (
+ FindTreatments, 'get-treatment', '')
@register.simple_tag(takes_context=True)
def dynamic_table_document(
context, caption, associated_model, key, value,
- table_cols='TABLE_COLS', output='html', large=False):
+ table_cols='TABLE_COLS', output='html', large=False,
+ col_prefix=''):
if not table_cols:
table_cols = 'TABLE_COLS'
model, url, url_full = ASSOCIATED_MODELS[associated_model]
- grid = JQueryJqGrid(None, None, model, table_cols=table_cols)
+ grid = JQueryJqGrid(None, None, model, table_cols=table_cols,
+ col_prefix=col_prefix)
source = unicode(reverse_lazy(url))
source_full = unicode(reverse_lazy(url_full)) if url_full else ''
source_attrs = mark_safe('?submited=1&{}={}'.format(key, value))
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index 0c4bbda08..dbe3df4a5 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -75,6 +75,32 @@ def create_user():
return username, password, user
+class WizardTestFormData(object):
+ """
+ Test set to simulate wizard steps
+ """
+ def __init__(self, name, form_datas, ignored=[], extra_tests=[]):
+ """
+ :param name: explicit name of the test
+ :param form_datas: dict with data for each step - dict key are wizard
+ step name
+ :param ignored: steps to be ignored in wizard processing
+ :param extra_tests: list of extra tests. Theses tests must be functions
+ accepting two parameters: the current test object and the final step
+ response
+ """
+ self.form_datas = form_datas
+ self.ignored = ignored[:]
+ self.extra_tests = extra_tests
+
+ def tests(self, test_object, final_step_response):
+ """
+ Specific tests for theses datas. Raise Exception if not OK.
+ """
+ for test in self.extra_tests:
+ test(test_object, final_step_response)
+
+
class WizardTest(object):
url_name = None
wizard_name = ''
@@ -95,7 +121,9 @@ class WizardTest(object):
def test_wizard(self):
url = reverse(self.url_name)
self.pre_wizard()
- for form_data, ignored in self.form_datas:
+ for test_form_data in self.form_datas:
+ form_data = test_form_data.form_datas
+ ignored = test_form_data.ignored
for idx, step in enumerate(self.steps):
current_step, current_form = step
if current_step in ignored:
@@ -138,6 +166,7 @@ class WizardTest(object):
'/{}/{}'.format(self.url_name, next_form))
else:
response = self.client.post(url, data, follow=True)
+ test_form_data.tests(self, response)
self.post_wizard()
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 8634125cd..6426fef8f 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -528,7 +528,7 @@ HIERARCHIC_FIELDS = ['periods', 'period', 'unit', 'material_types',
def get_item(model, func_name, default_name, extra_request_keys=[],
- base_request={}, bool_fields=[], reversed_bool_fields=[],
+ base_request=None, bool_fields=[], reversed_bool_fields=[],
dated_fields=[], associated_models=[], relative_session_names=[],
specific_perms=[], own_table_cols=None, relation_types_prefix={}):
"""
@@ -577,10 +577,12 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
my_extra_request_keys = copy(model.EXTRA_REQUEST_KEYS)
else:
my_extra_request_keys = copy(extra_request_keys)
- if not base_request and hasattr(model, 'BASE_REQUEST'):
+ if base_request is None and hasattr(model, 'BASE_REQUEST'):
my_base_request = copy(model.BASE_REQUEST)
- else:
+ elif base_request is not None:
my_base_request = copy(base_request)
+ else:
+ my_base_request = {}
if not bool_fields and hasattr(model, 'BOOL_FIELDS'):
my_bool_fields = model.BOOL_FIELDS[:]
else:
@@ -677,7 +679,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
request.session[default_name].split('-')[-1]}
else:
dct = {"pk": request.session[default_name]}
- elif dct == base_request:
+ elif dct == (base_request or {}):
# a parent item may be selected in the default menu
for name, key in my_relative_session_names:
if name in request.session and request.session[name]:
@@ -910,6 +912,14 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
keys = [keys]
my_vals = []
for k in keys:
+ if hasattr(model, 'EXTRA_REQUEST_KEYS') \
+ and k in model.EXTRA_REQUEST_KEYS:
+ k = model.EXTRA_REQUEST_KEYS[k]
+ if type(k) in (list, tuple):
+ k = k[0]
+ for filtr in ('__icontains', '__contains'):
+ if k.endswith(filtr):
+ k = k[:len(k) - len(filtr)]
vals = [item]
# foreign key may be divided by "." or "__"
splitted_k = []
@@ -929,10 +939,14 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
v = v()
new_vals.append(v)
elif val:
- val = getattr(val, ky)
- if callable(val):
- val = val()
- new_vals.append(val)
+ try:
+ val = getattr(val, ky)
+ if callable(val):
+ val = val()
+ new_vals.append(val)
+ except AttributeError:
+ # must be a query key such as "contains"
+ pass
vals = new_vals
# manage last related objects
if vals and hasattr(vals[0], 'all'):
@@ -995,9 +1009,9 @@ def get_item(model, func_name, default_name, extra_request_keys=[],
# foreign key may be divided by "." or "__"
for tc in table_col:
if '.' in tc:
- tab_cols.append(tc.split('.')[-1])
+ tab_cols += tc.split('.')
elif '__' in tc:
- tab_cols.append(tc.split('__')[-1])
+ tab_cols += tc.split('__')
else:
tab_cols.append(tc)
k = "__".join(tab_cols)
@@ -1118,7 +1132,6 @@ def show_item(model, name, extra_dct=None):
context_instance = RequestContext(request)
context_instance.update(dct)
context_instance['output'] = 'html'
- filename = ""
if hasattr(item, 'history_object'):
filename = item.history_object.associated_filename
else:
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index 1183836bc..be0ab8cba 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -19,12 +19,15 @@
# See the file COPYING for details.
+import logging
+
from django import forms
from django.conf import settings
-from django.core.urlresolvers import reverse
+from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import fields
from django.forms import ClearableFileInput
-from django.forms.widgets import flatatt
+from django.forms.widgets import flatatt, \
+ CheckboxSelectMultiple as CheckboxSelectMultipleBase
from django.template import Context, loader
from django.template.defaultfilters import slugify
from django.utils.encoding import smart_unicode
@@ -36,6 +39,8 @@ from django.utils.translation import ugettext_lazy as _
from ishtar_common import models
+logger = logging.getLogger(__name__)
+
reverse_lazy = lazy(reverse, unicode)
@@ -56,6 +61,20 @@ class Select2Multiple(forms.SelectMultiple):
return super(Select2Multiple, self).render(name, value, attrs,
choices)
+class CheckboxSelectMultiple(CheckboxSelectMultipleBase):
+ """
+ Fix initialization bug.
+ Should be corrected on recent Django version.
+ TODO: test and remove (test case: treatment type not keep on modif)
+ """
+ def render(self, name, value, attrs=None, choices=()):
+ if type(value) in (str, unicode):
+ value = value.split(',')
+ if type(value) not in (list, tuple):
+ value = [value]
+ return super(CheckboxSelectMultiple, self).render(name, value, attrs,
+ choices)
+
class MultipleAutocompleteField(forms.MultipleChoiceField):
def __init__(self, *args, **kwargs):
@@ -322,7 +341,6 @@ class JQueryTown(forms.TextInput):
@classmethod
def encode_source(cls, source):
- encoded_src = ''
if isinstance(source, list):
encoded_src = JSONEncoder().encode(source)
elif isinstance(source, str) \
@@ -515,7 +533,8 @@ 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, sortname="__default__"):
+ multiple_select=False, sortname="__default__",
+ col_prefix=''):
"""
JQueryJqGrid widget init.
@@ -531,6 +550,7 @@ class JQueryJqGrid(forms.RadioSelect):
:param source_full: url to get full listing
:param multiple_select:
:param sortname: column name (model attribute) to use to sort
+ :param col_prefix: prefix to remove to col_names
"""
super(JQueryJqGrid, self).__init__(attrs=attrs)
self.source = source
@@ -546,6 +566,9 @@ class JQueryJqGrid(forms.RadioSelect):
self.new, self.new_message = new, new_message
self.source_full = source_full
self.sortname = sortname
+ self.col_prefix = col_prefix
+ if self.col_prefix and not self.col_prefix.endswith('__'):
+ self.col_prefix += "__"
def get_cols(self, python=False):
jq_col_names, extra_cols = [], []
@@ -563,24 +586,26 @@ class JQueryJqGrid(forms.RadioSelect):
keys = col_name.split('__')
if '.' in col_name:
keys = col_name.split('.')
- f_name = ''
for key in keys:
if hasattr(field, 'rel') and field.rel:
field = field.rel.to
try:
field = field._meta.get_field(key)
field_verbose_name = field.verbose_name
- f_name = field.name
except (fields.FieldDoesNotExist, AttributeError):
if hasattr(field, key + '_lbl'):
- f_name = key
field_verbose_name = getattr(field, key + '_lbl')
else:
continue
if field_name:
field_name += "__"
- field_name += f_name
+ if col_name.startswith(self.col_prefix):
+ field_name += col_name[len(self.col_prefix):]
+ else:
+ field_name += col_name
field_verbose_names.append(unicode(field_verbose_name))
+ if not field_name:
+ field_name = "__".join(col_names)
if field_name in col_labels:
jq_col_names.append(unicode(col_labels[field_name]))
elif col_names and col_names[0] in col_labels:
@@ -618,7 +643,11 @@ class JQueryJqGrid(forms.RadioSelect):
col_idx = col_idx and ", ".join(col_idx) or ""
dct['encoding'] = settings.ENCODING or 'utf-8'
- dct['source'] = unicode(self.source)
+ try:
+ dct['source'] = unicode(self.source)
+ except NoReverseMatch:
+ logger.warning('Cannot resolve source for {} widget'.format(
+ self.form))
if unicode(self.source_full) and unicode(self.source_full) != 'None':
dct['source_full'] = unicode(self.source_full)
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index c065459f6..2fbe30e0e 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -18,6 +18,7 @@
# See the file COPYING for details.
import datetime
+import logging
# from functools import wraps
from django.conf import settings
@@ -38,6 +39,8 @@ from django.utils.datastructures import MultiValueDict as BaseMultiValueDict
from django.utils.translation import ugettext_lazy as _
import models
+logger = logging.getLogger(__name__)
+
class MultiValueDict(BaseMultiValueDict):
def get(self, *args, **kwargs):
@@ -126,6 +129,8 @@ class Wizard(NamedUrlWizardView):
current_obj_slug = ''
file_storage = default_storage
+ saved_args = {} # argument to pass on object save
+
'''
# buggy and unecessary...
def __init__(self, *args, **kwargs):
@@ -165,6 +170,13 @@ class Wizard(NamedUrlWizardView):
return super(Wizard, self).dispatch(request, *args, **kwargs)
+ def get_form_kwargs(self, step=None):
+ kwargs = super(Wizard, self).get_form_kwargs(step)
+ if hasattr(self.form_list[step], 'need_user_for_initialization') and\
+ self.form_list[step].need_user_for_initialization:
+ kwargs['user'] = self.request.user
+ return kwargs
+
def get_prefix(self, *args, **kwargs):
"""As the class name can interfere when reused prefix with the url_name
"""
@@ -194,7 +206,7 @@ class Wizard(NamedUrlWizardView):
self.request.session['CURRENT_ACTION'] = self.get_wizard_name()
step = self.steps.first
current_step = self.steps.current
- dct = {'current_step': self.form_list[current_step],
+ dct = {'current_step_label': self.form_list[current_step].form_label,
'wizard_label': self.label,
'current_object': self.get_current_object(),
'is_search': current_step.startswith('selec-')
@@ -209,7 +221,7 @@ class Wizard(NamedUrlWizardView):
or (previous_steps and
previous_steps[-1] == self.form_list[step]):
break
- previous_steps.append(self.form_list[step])
+ previous_steps.append(self.form_list[step].form_label)
previous_step_counter += 1
if previous_step_counter >= len(self.steps):
break
@@ -250,7 +262,7 @@ class Wizard(NamedUrlWizardView):
if step == next_step:
current_step_passed = True
elif current_step_passed:
- next_steps.append(self.form_list[next_step])
+ next_steps.append(self.form_list[next_step].form_label)
next_step = self.get_next_step(next_step)
context.update({'next_steps': next_steps})
# not last step: validation
@@ -483,9 +495,12 @@ class Wizard(NamedUrlWizardView):
elif type(dct[k]) not in (list, tuple):
dct[k] = [dct[k]]
setattr(obj, k, dct[k])
+ if hasattr(obj, 'pre_save'):
+ obj.pre_save()
try:
obj.full_clean()
- except ValidationError:
+ except ValidationError as e:
+ logger.warning(unicode(e))
return self.render(form_list[-1])
for dependant_item in other_objs:
c_item = getattr(obj, dependant_item)
@@ -543,12 +558,19 @@ class Wizard(NamedUrlWizardView):
dct[dependant_item] = c_item
if 'pk' in dct:
dct.pop('pk')
+ saved_args = self.saved_args.copy()
+ for k in saved_args:
+ if k in dct:
+ saved_args[k] = dct.pop(k)
obj = self.get_saved_model()(**dct)
+ if hasattr(obj, 'pre_save'):
+ obj.pre_save()
try:
obj.full_clean()
- except ValidationError:
+ except ValidationError as e:
+ logger.warning(unicode(e))
return self.render(form_list[-1])
- obj.save()
+ obj.save(**saved_args)
for k in adds:
getattr(obj, k).add(adds[k])
# necessary to manage interaction between models like
@@ -561,6 +583,12 @@ class Wizard(NamedUrlWizardView):
old_m2ms = {}
for model in whole_associated_models:
related_model = getattr(obj, model + 's')
+ # manage through
+ if hasattr(related_model, 'through') and related_model.through:
+ related_set_name = str(
+ related_model.through.__name__ + '_set').lower()
+ if hasattr(obj, related_set_name):
+ related_model = getattr(obj, related_set_name)
# clear real m2m
if hasattr(related_model, 'clear'):
old_m2ms[model] = []
@@ -587,6 +615,9 @@ class Wizard(NamedUrlWizardView):
if value not in m2m_items[key]:
if type(value) == dict:
model = related_model.model
+ if hasattr(related_model, 'through') and \
+ related_model.through:
+ model = related_model.through
# not m2m -> foreign key
if not hasattr(related_model, 'clear'):
assert hasattr(model, 'MAIN_ATTR'), \
@@ -611,6 +642,11 @@ class Wizard(NamedUrlWizardView):
else:
if issubclass(model, models.BaseHistorizedItem):
value['history_modifier'] = self.request.user
+ if hasattr(model, 'RELATIVE_MODELS') and \
+ self.get_saved_model() in \
+ model.RELATIVE_MODELS:
+ value[model.RELATIVE_MODELS[
+ self.get_saved_model()]] = obj
value = model.objects.create(**value)
value.save()
# check that an item is not add multiple times (forged forms)
@@ -626,6 +662,7 @@ class Wizard(NamedUrlWizardView):
self.request.session[self.current_obj_slug] = unicode(obj.pk)
self.request.session[self.get_object_name(obj)] = unicode(obj.pk)
dct = {'item': obj}
+ self.current_object = obj
# force evaluation of lazy urls
wizard_done_window = unicode(self.wizard_done_window)
if wizard_done_window:
@@ -980,8 +1017,18 @@ class Wizard(NamedUrlWizardView):
if not hasattr(obj, key):
return initial
keys = c_form.form.base_fields.keys()
- query = getattr(obj, key)
- if not obj._meta.ordering:
+ related = getattr(obj, key)
+ # manage through
+ through = False
+ if hasattr(related, 'through') and related.through:
+ related_set_name = str(
+ related.through.__name__ + '_set').lower()
+ if hasattr(obj, related_set_name):
+ through = True
+ related = getattr(obj, related_set_name)
+
+ query = related
+ if not through and not obj._meta.ordering:
query = query.order_by('pk')
for child_obj in query.all():
if not keys: