summaryrefslogtreecommitdiff
path: root/ishtar/furnitures/forms.py
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2011-06-24 14:37:16 +0200
committerÉtienne Loks <etienne.loks@peacefrogs.net>2011-06-24 14:37:16 +0200
commit95773b4ccd0beaa31f76c93a7c9b5e24211401dc (patch)
tree6b4fc14f42da9d91ab2bb4b989ffeeb42947392f /ishtar/furnitures/forms.py
parent7af17b15fa5cb03050b0fe90d38ab9f37dc51e74 (diff)
downloadIshtar-95773b4ccd0beaa31f76c93a7c9b5e24211401dc.tar.bz2
Ishtar-95773b4ccd0beaa31f76c93a7c9b5e24211401dc.zip
Sources creation for Operation (refs #497) - restructuration (refs #57)
Diffstat (limited to 'ishtar/furnitures/forms.py')
-rw-r--r--ishtar/furnitures/forms.py709
1 files changed, 0 insertions, 709 deletions
diff --git a/ishtar/furnitures/forms.py b/ishtar/furnitures/forms.py
deleted file mode 100644
index 3d663d089..000000000
--- a/ishtar/furnitures/forms.py
+++ /dev/null
@@ -1,709 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# Copyright (C) 2010-2011 É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
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# See the file COPYING for details.
-
-"""
-Forms definition
-"""
-import datetime
-import re
-from itertools import groupby
-
-from django.core.urlresolvers import reverse
-from django.core import validators
-from django.core.exceptions import ObjectDoesNotExist
-from django.utils import formats
-from django.utils.functional import lazy
-from django.utils.translation import ugettext_lazy as _
-from django.shortcuts import render_to_response
-from django.template import Context, RequestContext, loader
-from django.db.models import Max
-from django import forms
-from django.core.mail import send_mail
-from django.forms.formsets import formset_factory, BaseFormSet, \
- DELETION_FIELD_NAME
-from django.contrib.auth.models import User
-from django.contrib.sites.models import Site
-
-from formwizard.forms import NamedUrlSessionFormWizard
-
-import models
-import widgets
-from ishtar import settings
-
-reverse_lazy = lazy(reverse, unicode)
-
-def clean_duplicated(formset, key_names):
- """Checks for duplicated."""
- if any(formset.errors):
- return
- items = []
- for i in range(0, formset.total_form_count()):
- form = formset.forms[i]
- if not form.is_valid():
- continue
- item = [key_name in form.cleaned_data and form.cleaned_data[key_name]
- for key_name in key_names]
- if not [v for v in item if v]:
- continue
- if item in items:
- raise forms.ValidationError, \
- _("There are identical items.")
- items.append(item)
-
-regexp_name = re.compile(r'^[\w\- ]+$', re.UNICODE)
-name_validator = validators.RegexValidator(regexp_name,
-_(u"Enter a valid name consisting of letters, spaces and hyphens."), 'invalid')
-
-class FloatField(forms.FloatField):
- """
- Allow the use of comma for separating float fields
- """
- def clean(self, value):
- if value:
- value = value.replace(',', '.').replace('%', '')
- return super(FloatField, self).clean(value)
-
-class FinalForm(forms.Form):
- final = True
- form_label = _("Confirm")
-
-class FormSet(BaseFormSet):
- def add_fields(self, form, index):
- super(FormSet, self).add_fields(form, index)
- form.fields[DELETION_FIELD_NAME].label = ''
- form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget()
-
-class SearchWizard(NamedUrlSessionFormWizard):
- model = None
-
- def get_wizard_name(self):
- """
- As the class name can interfere when reused, use the url_name
- """
- return self.url_name
-
- def get_template(self, request, storage):
- templates = ['search.html']
- return templates
-
-class Wizard(NamedUrlSessionFormWizard):
- model = None
-
- def get_wizard_name(self):
- """
- As the class name can interfere when reused, use the url_name
- """
- return self.url_name
-
- def get_template(self, request, storage):
- templates = ['default_wizard.html']
- current_step = storage.get_current_step() or self.get_first_step(
- request, storage)
- if current_step == self.get_last_step(request, storage):
- templates = ['confirm_wizard.html'] + templates
- return templates
-
- def get_template_context(self, request, storage, form=None):
- """
- Add previous and current steps to manage the wizard path
- """
- context = super(Wizard, self).get_template_context(request, storage,
- form)
- step = self.get_first_step(request, storage)
- current_step = storage.get_current_step() or self.get_first_step(
- request, storage)
- context.update({'current_step':self.form_list[current_step]})
- if step == current_step:
- return context
- previous_steps = []
- while step:
- if step == current_step:
- break
- previous_steps.append(self.form_list[step])
- step = self.get_next_step(request, storage, step)
- context.update({'previous_steps':previous_steps})
- # not last step: validation
- if step != self.get_last_step(request, storage):
- return context
- final_form_list = []
- for form_key in self.get_form_list(request, storage).keys():
- form_obj = self.get_form(request, storage, step=form_key,
- data=storage.get_step_data(form_key),
- files=storage.get_step_files(form_key))
- form_obj.is_valid()
- final_form_list.append(form_obj)
- last_form = final_form_list[-1]
- context.update({'datas':self.get_formated_datas(final_form_list)})
- if hasattr(last_form, 'confirm_msg'):
- context.update({'confirm_msg':last_form.confirm_msg})
- if hasattr(last_form, 'confirm_end_msg'):
- context.update({'confirm_end_msg':last_form.confirm_end_msg})
- return context
-
- def get_formated_datas(self, forms):
- """
- Get the data to present in the last page
- """
- datas = []
- for form in forms:
- form_datas = []
- base_form = hasattr(form, 'forms') and form.forms[0] or form
- associated_models = hasattr(base_form, 'associated_models') and \
- base_form.associated_models or {}
- if not hasattr(form, 'cleaned_data') and hasattr(form, 'forms'):
- cleaned_datas = [frm.cleaned_data for frm in form.forms
- if frm.is_valid()]
- if not cleaned_datas:
- continue
- elif not hasattr(form, 'cleaned_data'):
- continue
- else:
- cleaned_datas = type(form.cleaned_data) == list and \
- form.cleaned_data \
- or [form.cleaned_data]
- for cleaned_data in cleaned_datas:
- if not cleaned_data:
- continue
- if form_datas:
- form_datas.append(("", "", "spacer"))
- items = hasattr(base_form, 'fields') and \
- base_form.fields.keyOrder or cleaned_data.keys()
- for key in items:
- lbl = None
- if key.startswith('hidden_'):
- continue
- if hasattr(base_form, 'fields') and key in base_form.fields:
- lbl = base_form.fields[key].label
- if not lbl:
- continue
- value = cleaned_data[key]
- if not value and value != False:
- continue
- if type(value) == bool:
- if value == True:
- value = _("Yes")
- elif value == False:
- value = _("No")
- elif key in associated_models:
- item = associated_models[key].objects.get(pk=value)
- if hasattr(item, 'short_label'):
- value = item.short_label()
- else:
- value = unicode(item)
- form_datas.append((lbl, value, ''))
- if form_datas:
- datas.append((form.form_label, form_datas))
- return datas
-
- def get_extra_model(self, dct, request, storage, form_list):
- dct['history_modifier'] = request.user
- return dct
-
- def done(self, request, storage, form_list, return_object=False, **kwargs):
- """
- Save to the model
- """
- dct, m2m, whole_associated_models = {}, [], []
- for form in form_list:
- if not form.is_valid():
- return self.render(request, storage, form)
- base_form = hasattr(form, 'forms') and form.forms[0] or form
- associated_models = hasattr(base_form, 'associated_models') and \
- base_form.associated_models or {}
- if hasattr(form, 'forms'):
- multi = False
- if form.forms:
- frm = form.forms[0]
- if hasattr(frm, 'base_model') and frm.base_model:
- whole_associated_models.append(frm.base_model)
- else:
- whole_associated_models += associated_models.keys()
- fields = frm.fields.copy()
- if 'DELETE' in fields:
- fields.pop('DELETE')
- multi = len(fields) > 1
- if multi:
- assert hasattr(frm, 'base_model'), \
- u"Must define a base_model for " + unicode(frm.__class__)
- for frm in form.forms:
- if not frm.is_valid():
- continue
- vals = {}
- if "DELETE" in frm.cleaned_data:
- if frm.cleaned_data["DELETE"]:
- continue
- frm.cleaned_data.pop('DELETE')
- for key in frm.cleaned_data:
- value = frm.cleaned_data[key]
- if not value and value != False:
- continue
- if key in associated_models:
- value = associated_models[key].objects.get(pk=value)
- if multi:
- vals[key] = value
- else:
- m2m.append((key, value))
- if multi and vals:
- m2m.append((frm.base_model, vals))
- elif type(form.cleaned_data) == dict:
- for key in form.cleaned_data:
- if key.startswith('hidden_'):
- continue
- value = form.cleaned_data[key]
- if key in associated_models:
- if value:
- value = associated_models[key].objects.get(pk=value)
- else:
- value = None
- dct[key] = value
- return self.save_model(dct, m2m, whole_associated_models, request,
- storage, form_list, return_object)
-
- def get_saved_model(self):
- """
- Permit a distinguo when saved model is not the base selected model
- """
- return self.model
-
- def get_current_saved_object(self, request, storage):
- """
- Permit a distinguo when saved model is not the base selected model
- """
- return self.get_current_object(request, storage)
-
- def save_model(self, dct, m2m, whole_associated_models, request, storage,
- form_list, return_object):
- dct = self.get_extra_model(dct, request, storage, form_list)
- obj = self.get_current_saved_object(request, storage)
-
- # manage dependant items
- other_objs = {}
- for k in dct.keys():
- if '__' not in k:
- continue
- vals = k.split('__')
- assert len(vals) == 2, "Only one level of dependant item is managed"
- dependant_item, key = vals
- if dependant_item not in other_objs:
- other_objs[dependant_item] = {}
- other_objs[dependant_item][key] = dct.pop(k)
- if obj:
- for k in dct:
- if k.startswith('pk'):
- continue
- setattr(obj, k, dct[k])
- for dependant_item in other_objs:
- c_item = getattr(obj, dependant_item)
- # manage ManyToMany if only one associated
- if hasattr(c_item, "all"):
- c_items = c_item.all()
- if len(c_items) != 1:
- continue
- c_item = c_items[0]
- if c_item:
- # to check #
- for k in other_objs[dependant_item]:
- setattr(c_item, k, other_objs[dependant_item][k])
- c_item.save()
- else:
- m = getattr(self.model, dependant_item)
- if hasattr(m, 'related'):
- c_item = m.related.model(**other_objs[dependant_item])
- setattr(obj, dependant_item, c_item)
- obj.save()
- obj.save()
- else:
- adds = {}
- for dependant_item in other_objs:
- m = getattr(self.model, dependant_item)
- model = m.field.rel.to
- c_dct = other_objs[dependant_item].copy()
- if hasattr(model, 'history'):
- c_dct['history_modifier'] = request.user
- c_item = model(**c_dct)
- c_item.save()
- if hasattr(m, 'through'):
- adds[dependant_item] = c_item
- elif hasattr(m, 'field'):
- dct[dependant_item] = c_item
- if 'pk' in dct:
- dct.pop('pk')
- obj = self.get_saved_model()(**dct)
- obj.save()
- for k in adds:
- getattr(obj, k).add(adds[k])
- # necessary to manage interaction between models like
- # material_index management for baseitems
- obj.save()
- m2m_items = {}
- for model in whole_associated_models:
- getattr(obj, model+'s').clear()
- for key, value in m2m:
- if key not in m2m_items:
- if type(key) == dict:
- vals = []
- for item in getattr(obj, key+'s').all():
- v = {}
- for k in value.keys():
- v[k] = getattr(item, k)
- vals.append(v)
- m2m_items[key] = vals
- else:
- m2m_items[key] = getattr(obj, key+'s').all()
- if value not in m2m_items[key]:
- if type(value) == dict:
- model = getattr(obj, key+'s').model
- if issubclass(model, models.BaseHistorizedItem):
- value['history_modifier'] = request.user
- value = model.objects.create(**value)
- value.save()
- getattr(obj, key+'s').add(value)
- # necessary to manage interaction between models like
- # material_index management for baseitems
- obj.save()
- res = render_to_response('wizard_done.html', {},
- context_instance=RequestContext(request))
- return return_object and (obj, res) or res
-
- def get_deleted(self, keys):
- """
- Get the deleted and non-deleted items in formsets
- """
- not_to_delete, to_delete = set(), set()
- for key in keys:
- items = key.split('-')
- if len(items) < 2 or items[-2] in to_delete:
- continue
- idx = items[-2]
- try:
- int(idx)
- except:
- continue
- if items[-1] == u'DELETE':
- to_delete.add(idx)
- if idx in not_to_delete:
- not_to_delete.remove(idx)
- elif idx not in not_to_delete:
- not_to_delete.add(idx)
- return (to_delete, not_to_delete)
-
- def get_form(self, request, storage, step=None, data=None, files=None):
- """
- Manage formset
- """
- if data:
- data = data.copy()
- if not step:
- step = self.determine_step(request, storage)
- form = self.get_form_list(request, storage)[step]
- if hasattr(form, 'management_form'):
- # manage deletion
- to_delete, not_to_delete = self.get_deleted(data.keys())
- # raz deleted fields
- for key in data.keys():
- items = key.split('-')
- if len(items) < 2 or items[-2] not in to_delete:
- continue
- data.pop(key)
- if to_delete:
- # reorganize
- for idx, number in enumerate(sorted(not_to_delete)):
- idx = unicode(idx)
- if idx == number:
- continue
- for key in data.keys():
- items = key.split('-')
- if len(items) > 2 and number == items[-2]:
- items[-2] = unicode(idx)
- k = u'-'.join(items)
- data[k] = data.pop(key)[0]
- # get a form key
- base_key = form.form.base_fields.keys()[0]
- init = self.get_form_initial(request, storage, step)
- total_field = len([key for key in data.keys()
- if base_key in key.split('-')
- and data[key]])
- if init and not to_delete:
- total_field = max((total_field, len(init)))
- data[step + u'-INITIAL_FORMS'] = unicode(total_field)
- data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1)
- data = data or None
- form = super(Wizard, self).get_form(request, storage, step, data, files)
- return form
-
- def render_next_step(self, request, storage, form, **kwargs):
- """
- Manage the modify or delete button in formset: next_step = current_step
- """
- if request.POST.has_key('formset_modify') \
- and request.POST['formset_modify'] \
- or [key for key in request.POST.keys()
- if key.endswith('DELETE') and request.POST[key]]:
- return self.render(request, storage, form, **kwargs)
- return super(Wizard, self).render_next_step(request, storage, form,
- **kwargs)
-
- def process_post_request(self, request, storage, *args, **kwargs):
- """
- Convert numerical step number to step name
- """
- post_data = request.POST.copy()
- if request.POST.has_key('form_prev_step'):
- try:
- step_number = int(request.POST['form_prev_step'])
- post_data['form_prev_step'] = self.get_form_list(request,
- storage).keys()[step_number]
- except ValueError:
- pass
- request.POST = post_data
- return super(Wizard, self).process_post_request(request, storage, *args,
- **kwargs)
- @classmethod
- def session_has_key(cls, request, storage, form_key, key=None, multi=None):
- """
- Check if the session has value of a specific form and (if provided)
- of a key
- """
- test = storage.prefix in request.session \
- and 'step_data' in request.session[storage.prefix] \
- and form_key in request.session[storage.prefix]['step_data']
- if not key or not test:
- return test
- key = key.startswith(form_key) and key or \
- not multi and form_key + '-' + key or \
- form_key + '-0-' + key #only check if the first field is available
- return key in request.session[storage.prefix]['step_data'][form_key]
-
- @classmethod
- def session_get_value(cls, request, storage, form_key, key, multi=False):
- """
- Get the value of a specific form
- """
- if not cls.session_has_key(request, storage, form_key, key, multi):
- return
- if not multi:
- key = key.startswith(form_key) and key or form_key + '-' + key
- return request.session[storage.prefix]['step_data'][form_key][key]
- vals = []
- for k in request.session[storage.prefix]['step_data'][form_key]:
- if k.startswith(form_key) and k.endswith(key) and \
- request.session[storage.prefix]['step_data'][form_key][k]:
- vals.append(request.session[storage.prefix]['step_data']\
- [form_key][k])
- return vals
-
- def get_current_object(self, request, storage):
- """
- Get the current object for an instancied wizard
- """
- current_obj = None
- main_form_key = 'selec-' + self.url_name
- try:
- idx = int(self.session_get_value(request, storage, main_form_key,
- 'pk'))
- current_obj = self.model.objects.get(pk=idx)
- except(TypeError, ValueError, ObjectDoesNotExist):
- pass
- return current_obj
-
- def get_form_initial(self, request, storage, step):
- current_obj = self.get_current_object(request, storage)
- current_step = storage.get_current_step() or self.get_first_step(
- request, storage)
- if step.startswith('selec-') and step in self.form_list \
- and 'pk' in self.form_list[step].associated_models:
- model_name = self.form_list[step].associated_models['pk'
- ].__name__.lower()
- if step == current_step:
- self.reset_wizard(request, storage)
- val = model_name in request.session and request.session[model_name]
- if val:
- return {'pk':val}
- elif current_obj:
- return self.get_instanced_init(current_obj, request, storage,
- step)
- current_form = self.form_list[current_step]
- if hasattr(current_form, 'currents'):
- initial = {}
- for key in current_form.currents:
- model_name = current_form.currents[key].__name__.lower()
- val = model_name in request.session and \
- request.session[model_name]
- if val:
- initial[key] = val
- if initial:
- return initial
- return super(Wizard, self).get_form_initial(request, storage, step)
-
- def get_instanced_init(self, obj, request, storage, step):
- """
- Get initial data from an init
- """
- current_step = storage.get_current_step() or self.get_first_step(
- request, storage)
- c_form = self.form_list[current_step]
- # make the current object the default item for the session
- obj_name = obj.__class__.__name__.lower()
- # prefer a specialized name if available
- prefixes = storage.prefix.split('_')
- if len(prefixes) > 1 and prefixes[-2].startswith(obj_name):
- obj_name = prefixes[-2]
- request.session[obj_name] = unicode(obj.pk)
- initial = {}
- if request.POST or (step in request.session[storage.prefix] and\
- request.session[storage.prefix]['step_data'][step]):
- return {}
- if hasattr(c_form, 'base_fields'):
- for base_field in c_form.base_fields.keys():
- fields = base_field.split('__')
- value = obj
- for field in fields:
- if not hasattr(value, field) or \
- getattr(value, field) == None:
- value = obj
- break
- value = getattr(value, field)
- if value == obj:
- continue
- if hasattr(value, 'pk'):
- value = value.pk
- if value in (True, False):
- initial[base_field] = value
- elif value != None:
- initial[base_field] = unicode(value)
- elif hasattr(c_form, 'management_form'):
- initial = []
- key = current_step.split('-')[0]
- if not hasattr(obj, key):
- return initial
- keys = c_form.form.base_fields.keys()
- for child_obj in getattr(obj, key).order_by('pk').all():
- if not keys:
- break
- vals = {}
- if len(keys) == 1:
- # only one field: must be the id of the object
- vals[keys[0]] = unicode(child_obj.pk)
- else:
- for field in keys:
- if hasattr(child_obj, field):
- value = getattr(child_obj, field)
- if hasattr(value, 'pk'):
- value = value.pk
- if value != None:
- vals[field] = unicode(value)
- if vals:
- initial.append(vals)
- return initial
-
-def get_now():
- format = formats.get_format('DATE_INPUT_FORMATS')[0]
- value = datetime.datetime.now().strftime(format)
- return value
-
-class DeletionWizard(Wizard):
- def get_formated_datas(self, forms):
- datas = super(DeletionWizard, self).get_formated_datas(forms)
- self.current_obj = None
- for form in forms:
- if not hasattr(form, "cleaned_data"):
- continue
- for key in form.cleaned_data:
- if key == 'pk':
- model = form.associated_models['pk']
- self.current_obj = model.objects.get(pk=form.cleaned_data['pk'])
- if not self.current_obj:
- return datas
- res = {}
- for field in self.model._meta.fields + self.model._meta.many_to_many:
- if field.name not in self.fields:
- continue
- value = getattr(self.current_obj, field.name)
- if not value:
- continue
- if hasattr(value, 'all'):
- value = ", ".join([unicode(item) for item in value.all()])
- if not value:
- continue
- else:
- value = unicode(value)
- res[field.name] = (field.verbose_name, value, '')
- if not datas and self.fields:
- datas = [['', []]]
- for field in self.fields:
- if field in res:
- datas[0][1].append(res[field])
- return datas
-
- def done(self, request, storage, form_list, **kwargs):
- obj = self.get_current_object(request, storage)
- obj.delete()
- return render_to_response('wizard_delete_done.html', {},
- context_instance=RequestContext(request))
-
-class ClosingWizard(Wizard):
- # "close" an item
- # to be define in the overloaded class
- model = None
- fields = []
-
- def get_formated_datas(self, forms):
- datas = super(ClosingWizard, self).get_formated_datas(forms)
- self.current_obj = None
- for form in forms:
- if not hasattr(form, "cleaned_data"):
- continue
- for key in form.cleaned_data:
- if key == 'pk':
- model = form.associated_models['pk']
- self.current_obj = model.objects.get(
- pk=form.cleaned_data['pk'])
- if not self.current_obj:
- return datas
- res = {}
- for field in self.model._meta.fields + self.model._meta.many_to_many:
- if field.name not in self.fields:
- continue
- value = getattr(self.current_obj, field.name)
- if not value:
- continue
- if hasattr(value, 'all'):
- value = ", ".join([unicode(item) for item in value.all()])
- if not value:
- continue
- else:
- value = unicode(value)
- res[field.name] = (field.verbose_name, value, '')
- if not datas and self.fields:
- datas = [['', []]]
- for field in self.fields:
- if field in res:
- datas[0][1].append(res[field])
- return datas
-
- def done(self, request, storage, form_list, **kwargs):
- obj = self.get_current_object(request, storage)
- for form in form_list:
- if form.is_valid():
- if 'end_date' in form.cleaned_data and hasattr(obj, 'end_date'):
- obj.end_date = form.cleaned_data['end_date']
- obj.save()
- return render_to_response('wizard_closing_done.html', {},
- context_instance=RequestContext(request))
-