#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010-2013 Étienne Loks # 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 . # See the file COPYING for details. """ Operations forms definitions """ import datetime from django import forms from django.conf import settings from django.core import validators from django.core.exceptions import ObjectDoesNotExist from django.db.models import Max from django.forms.formsets import DELETION_FIELD_NAME, TOTAL_FORM_COUNT from django.shortcuts import render_to_response from django.template import RequestContext from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe from ishtar_common.models import valid_id, PersonType, Person, Town, \ DocumentTemplate from archaeological_files.models import File import models from widgets import ParcelWidget, SelectParcelWidget from ishtar_common import widgets from ishtar_common.forms import BaseFormSet, FinalForm, FormSet, \ ClosingDateFormSelection, formset_factory, get_now, reverse_lazy, \ get_form_selection, TableSelect from ishtar_common.forms_common import TownForm, TownFormSet, TownFormset, \ AuthorFormset, SourceForm, SourceSelect, \ SourceDeletionForm, get_town_field from archaeological_operations.utils import parse_parcels class ParcelField(forms.MultiValueField): def __init__(self, *args, **kwargs): if 'widget' not in kwargs: self.widget = ParcelWidget() return super(ParcelField, self).__init__(*args, **kwargs) def compress(data_list): return u"-".join(data_list) class ParcelForm(forms.Form): form_label = _("Parcels") base_model = 'parcel' 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, validators=[validators.MinValueValidator(1900), validators.MaxValueValidator(2100)]) section = forms.CharField(label=_(u"Section"), required=False, validators=[validators.MaxLengthValidator(4)]) parcel_number = forms.CharField(label=_(u"Parcel number"), required=False, validators=[validators.MaxLengthValidator(6)]) def __init__(self, *args, **kwargs): towns = None if 'data' in kwargs and 'TOWNS' in kwargs['data']: towns = kwargs['data']['TOWNS'] # clean data if not "real" data prefix_value = kwargs['prefix'] + '-town' if not [k for k in kwargs['data'].keys() if k.startswith(prefix_value) and kwargs['data'][k]]: kwargs['data'] = None if 'files' in kwargs: kwargs.pop('files') super(ParcelForm, self).__init__(*args, **kwargs) if towns: self.fields['town'].choices = [('', '--')] + towns def clean(self): """Check required fields""" if any(self.errors): return if not self.cleaned_data or (DELETION_FIELD_NAME in self.cleaned_data \ and self.cleaned_data[DELETION_FIELD_NAME]): return if not self.cleaned_data.get('parcel_number'): return {} for key in ('town', 'parcel_number', 'section'): if not key in self.cleaned_data or not self.cleaned_data[key]: raise forms.ValidationError(_(u"Town section and parcel number " u"fields are required.")) return self.cleaned_data class ParcelSelectionForm(forms.Form): _parcel_selection = forms.CharField(label=_(u"Full text input"), widget=SelectParcelWidget(attrs={'class':'parcel-select'}), max_length=100, help_text=_(u"example: \"2013: XD:1 to "\ u"13,24,33 to 39, YD:24\" or \"AB:24,AC:42\""), required=False) class ParcelFormSet(FormSet): SELECTION_FORM = ParcelSelectionForm def __init__(self, *args, **kwargs): super(FormSet, self).__init__(*args, **kwargs) self.extra_form = None if self.forms[0].__class__.__name__ == 'ParcelForm': self.selection_form = ParcelSelectionForm() self.extra_form = self.selection_form def as_table(self): # add dynamic widget render = self.selection_form.as_table() render += super(FormSet, self).as_table() return mark_safe(render) def as_p(self): # add dynamic widget render = self.selection_form.as_p() render += super(FormSet, self).as_p() return mark_safe(render) def as_ul(self): # add dynamic widget render = self.selection_form.as_ul() render += super(FormSet, self).as_ul() return mark_safe(render) def add_fields(self, form, index): super(FormSet, self).add_fields(form, index) def clean(self): # manage parcel selection last_town, parcels = None, [] if hasattr(self, 'cleaned_data') and self.cleaned_data: for parcel in reversed(self.cleaned_data): if parcel.get('town'): last_town = parcel.get('town') break if not last_town and 'town' in self.forms[0].fields.keys(): towns = self.forms[0].fields['town'].choices if towns: towns.pop(0) # remove first empty if towns: last_town = towns[0][0] if self.data.get('_parcel_selection'): parcels = parse_parcels(self.data['_parcel_selection']) if last_town: for idx, parcel in enumerate(parcels): parcel['town'] = last_town parcel['DELETE'] = False parcels[idx] = parcel c_max = self.total_form_count() # pop the last extra form extra_form = self.forms.pop() for idx, parcel in enumerate(parcels): form = self._construct_form(idx + c_max) for k in parcel: self.data[form.prefix+'-'+k] = parcel[k] # reconstruct with correct binded data form = self._construct_form(idx + c_max) form.cleaned_data = parcel self.forms.append(form) self._errors.append(None) self.forms.append(extra_form) self.data[self.prefix+'-'+TOTAL_FORM_COUNT] = c_max + len(parcels) self.management_form.data = self.data self.management_form.is_valid() # Checks that no parcels are duplicated. self.check_duplicate(('town', 'section', 'parcel_number', 'year'), _(u"There are identical parcels.")) if hasattr(self, 'cleaned_data') and self.cleaned_data: return self.cleaned_data ParcelFormSet = formset_factory(ParcelForm, can_delete=True, formset=ParcelFormSet) ParcelFormSet.form_label = _(u"Parcels") class OperationSelect(TableSelect): common_name = forms.CharField(label=_(u"Name (full text search)"), max_length=30) if settings.COUNTRY == 'fr': code_patriarche = forms.IntegerField(label="Code PATRIARCHE") towns = get_town_field() operation_type = forms.ChoiceField(label=_(u"Operation type"), choices=[]) in_charge = forms.IntegerField( widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', args=["_".join( [unicode(PersonType.objects.get(txt_idx='head_scientist').pk), unicode(PersonType.objects.get(txt_idx='sra_agent').pk)])]), associated_model=Person), label=_(u"In charge")) remains = forms.ChoiceField(label=_(u"Remains"), choices=[]) periods = forms.ChoiceField(label=_(u"Periods"), choices=[]) year = forms.IntegerField(label=_("Year")) start_before = forms.DateField(label=_(u"Started before"), widget=widgets.JQueryDate) start_after = forms.DateField(label=_(u"Started after"), widget=widgets.JQueryDate) end_before = forms.DateField(label=_(u"Ended before"), widget=widgets.JQueryDate) end_after = forms.DateField(label=_(u"Ended after"), widget=widgets.JQueryDate) parcel = ParcelField(label=_("Parcel (section/number)")) end_date = forms.NullBooleanField(label=_(u"Is open?")) def __init__(self, *args, **kwargs): super(OperationSelect, self).__init__(*args, **kwargs) self.fields['operation_type'].choices = models.OperationType.get_types() self.fields['operation_type'].help_text = models.OperationType.get_help() self.fields['remains'].choices = models.RemainType.get_types() self.fields['remains'].help_text = models.RemainType.get_help() self.fields['periods'].choices = models.Period.get_types() self.fields['periods'].help_text = models.Period.get_help() def get_input_ids(self): ids = super(OperationSelect, self).get_input_ids() ids.pop(ids.index('parcel')) ids.append('parcel_0') ids.append('parcel_1') return ids class OperationFormSelection(forms.Form): form_label = _(u"Operation search") associated_models = {'pk':models.Operation} currents = {'pk':models.Operation} pk = forms.IntegerField(label="", required=False, widget=widgets.JQueryJqGrid(reverse_lazy('get-operation'), OperationSelect, models.Operation, source_full=reverse_lazy('get-operation-full')), validators=[valid_id(models.Operation)]) def clean(self): cleaned_data = self.cleaned_data if 'pk' not in cleaned_data or not cleaned_data['pk']: raise forms.ValidationError(_(u"You should select an operation.")) return cleaned_data class OperationCodeInput(forms.TextInput): """Manage auto complete when changing year in form""" def render(self, *args, **kwargs): name, value = args base_name = '-'.join(name.split('-')[:-1]) rendered = super(OperationCodeInput, self).render(*args, **kwargs) js = u"""\n \n""" % {'base_name':base_name, 'name':name, 'url':reverse_lazy('get_available_operation_code')} return rendered + js class OperationFormGeneral(forms.Form): form_label = _(u"General") associated_models = {'in_charge':Person, 'associated_file':File, '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"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', args=["_".join( [unicode(PersonType.objects.get(txt_idx='head_scientist').pk), unicode(PersonType.objects.get(txt_idx='sra_agent').pk)])]), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) associated_file = forms.IntegerField(label=_(u"Archaelogical file"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), associated_model=File), validators=[valid_id(File)], required=False) operation_type = forms.ChoiceField(label=_(u"Operation type"), choices=[]) start_date = forms.DateField(label=_(u"Start date"), required=False, widget=widgets.JQueryDate) excavation_end_date = forms.DateField(label=_(u"Excavation end date"), required=False, widget=widgets.JQueryDate) report_delivery_date = forms.DateField(label=_(u"Report delivery date"), required=False, widget=widgets.JQueryDate) surface = forms.IntegerField(required=False, widget=widgets.AreaWidget, label=_(u"Total surface (m²)"), validators=[validators.MinValueValidator(0), validators.MaxValueValidator(999999999)]) year = forms.IntegerField(label=_(u"Year"), initial=lambda:datetime.datetime.now().year, validators=[validators.MinValueValidator(1900), validators.MaxValueValidator(2100)]) operation_code = forms.IntegerField(label=_(u"Operation code"), initial=models.Operation.get_available_operation_code, widget=OperationCodeInput) common_name = forms.CharField(label=_(u"Generic name"), required=False, 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") code_patriarche = forms.IntegerField(label=u"Code PATRIARCHE", required=False) code_dracar = forms.CharField(label=u"Code DRACAR", required=False, validators=[validators.MaxLengthValidator(10)]) eas_number = forms.CharField(label=u"Numéro de l'EA", required=False, validators=[validators.MaxLengthValidator(20)]) cira_date = forms.DateField(label=u"Date avis CIRA", required=False, widget=widgets.JQueryDate) cira_rapporteur = forms.IntegerField(label=u"Rapporteur CIRA", widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', args=["_".join( [unicode(PersonType.objects.get(txt_idx='head_scientist').pk), unicode(PersonType.objects.get(txt_idx='sra_agent').pk)])]), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, required=False) def __init__(self, *args, **kwargs): super(OperationFormGeneral, self).__init__(*args, **kwargs) self.fields['operation_type'].choices = models.OperationType.get_types() self.fields['operation_type'].help_text = models.OperationType.get_help() def clean(self): cleaned_data = self.cleaned_data # verify the logic between start date and excavation end date if cleaned_data['excavation_end_date']: if not self.cleaned_data['start_date']: raise forms.ValidationError(_(u"If you want to set an " u"excavation end date you have to provide a start date.")) if cleaned_data['excavation_end_date'] < cleaned_data['start_date']: raise forms.ValidationError(_(u"The excavation end date "\ u"cannot be before the start date.")) year = self.cleaned_data.get("year") operation_code = cleaned_data.get("operation_code") ops = models.Operation.objects.filter(year=year, operation_code=operation_code) # manage unique operation ID if 'pk' in cleaned_data and cleaned_data['pk']: ops = ops.exclude(pk=cleaned_data['pk']) if ops.count(): max_val = models.Operation.objects.filter(year=year).aggregate( Max('operation_code'))["operation_code__max"] msg = '' if year and max_val: msg = _(u"Operation code already exist for " u"year: %(year)d - use a value bigger than %(last_val)d") % { 'year':year, 'last_val':max_val} else: msg = _(u"Bad operation code") raise forms.ValidationError(msg) return self.cleaned_data class OperationFormPreventive(forms.Form): form_label = _(u"Preventive informations - excavation") cost = forms.IntegerField(label=_(u"Cost (€)"), required=False) scheduled_man_days = forms.IntegerField(label=_(u"Scheduled man-days"), required=False) optional_man_days = forms.IntegerField(label=_(u"Optional man-days"), required=False) effective_man_days = forms.IntegerField(label=_(u"Effective man-days"), required=False) if settings.COUNTRY == 'fr': fnap_financing = forms.FloatField(required=False, label=u"Pourcentage de financement FNAP", validators=[validators.MinValueValidator(0), validators.MaxValueValidator(100)]) class OperationFormPreventiveDiag(forms.Form): form_label = _("Preventive informations - diagnostic") if settings.COUNTRY == 'fr': zoning_prescription = forms.NullBooleanField(required=False, label=_(u"Prescription on zoning")) large_area_prescription = forms.NullBooleanField(required=False, label=_(u"Prescription on large area")) geoarchaeological_context_prescription = forms.NullBooleanField( required=False, label=_(u"Prescription on geoarchaeological context")) class SelectedTownForm(forms.Form): form_label = _("Towns") associated_models = {'town':Town} town = forms.ChoiceField(label=_("Town"), choices=(), validators=[valid_id(Town)]) def __init__(self, *args, **kwargs): towns = None if 'data' in kwargs and 'TOWNS' in kwargs['data']: towns = kwargs['data']['TOWNS'] # clean data if not "real" data prefix_value = kwargs['prefix'] + '-town' if not [k for k in kwargs['data'].keys() if k.startswith(prefix_value) and kwargs['data'][k]]: kwargs['data'] = None if 'files' in kwargs: kwargs.pop('files') super(SelectedTownForm, self).__init__(*args, **kwargs) if towns and towns != -1: self.fields['town'].choices = [('', '--')] + towns SelectedTownFormset = formset_factory(SelectedTownForm, can_delete=True, formset=TownFormSet) SelectedTownFormset.form_label = _(u"Towns") class SelectedParcelForm(forms.Form): form_label = _("Parcels") associated_models = {'parcel':models.Parcel} parcel = forms.ChoiceField(label=_("Parcel"), choices=(), validators=[valid_id(models.Parcel)]) def __init__(self, *args, **kwargs): parcels = None if 'data' in kwargs and 'PARCELS' in kwargs['data']: parcels = kwargs['data']['PARCELS'] # clean data if not "real" data prefix_value = kwargs['prefix'] + '-parcel' if not [k for k in kwargs['data'].keys() if k.startswith(prefix_value) and kwargs['data'][k]]: kwargs['data'] = None if 'files' in kwargs: kwargs.pop('files') super(SelectedParcelForm, self).__init__(*args, **kwargs) if parcels: self.fields['parcel'].choices = [('', '--')] + parcels SelectedParcelFormSet = formset_factory(SelectedParcelForm, can_delete=True, formset=ParcelFormSet) SelectedParcelFormSet.form_label = _("Parcels") SelectedParcelGeneralFormSet = formset_factory(ParcelForm, can_delete=True, formset=ParcelFormSet) SelectedParcelGeneralFormSet.form_label = _("Parcels") class RemainForm(forms.Form): form_label = _("Remain types") base_model = 'remain' associated_models = {'remain':models.RemainType} remain = forms.ChoiceField(label=_("Remain type"), required=False, choices=[]) def __init__(self, *args, **kwargs): super(RemainForm, self).__init__(*args, **kwargs) self.fields['remain'].choices = models.RemainType.get_types() self.fields['remain'].help_text = models.RemainType.get_help() class RemainFormSet(FormSet): def clean(self): """Checks that no remain types are duplicated.""" return self.check_duplicate(['remain_type'], _(u"There are identical remain types")) RemainFormset = formset_factory(RemainForm, can_delete=True, formset=RemainFormSet) RemainFormset.form_label = _("Remain types") class PeriodForm(forms.Form): form_label = _("Periods") base_model = 'period' associated_models = {'period':models.Period} period = forms.ChoiceField(label=_("Period"), required=False, choices=[]) def __init__(self, *args, **kwargs): super(PeriodForm, self).__init__(*args, **kwargs) self.fields['period'].choices = models.Period.get_types() self.fields['period'].help_text = models.Period.get_help() class PeriodFormSet(FormSet): def clean(self): """Checks that no period are duplicated.""" return self.check_duplicate(['period'], _(u"There are identical periods")) 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?") class OperationDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this operation?") #################################### # Source management for operations # #################################### class OperationSourceForm(SourceForm): pk = forms.IntegerField(required=False, widget=forms.HiddenInput) index = forms.IntegerField(label=_(u"Index")) hidden_operation_id = forms.IntegerField(label="", widget=forms.HiddenInput) def __init__(self, *args, **kwargs): super(OperationSourceForm, self).__init__(*args, **kwargs) keyOrder = self.fields.keyOrder keyOrder.pop(keyOrder.index('index')) keyOrder.insert(keyOrder.index('source_type') + 1, 'index') def clean(self): # manage unique operation ID cleaned_data = self.cleaned_data operation_id = cleaned_data.get("hidden_operation_id") index = cleaned_data.get("index") srcs = models.OperationSource.objects.filter(index=index, operation__pk=operation_id) if 'pk' in cleaned_data and cleaned_data['pk']: srcs = srcs.exclude(pk=cleaned_data['pk']) if srcs.count(): max_val = models.OperationSource.objects.filter( operation__pk=operation_id ).aggregate(Max('index'))["index__max"] operation = models.Operation.objects.get(pk=operation_id) raise forms.ValidationError(_(u"Index already exist for " "operation: %(operation)s - use a value bigger than %(last_val)d") % { "operation":unicode(operation), 'last_val':max_val}) return cleaned_data SourceOperationFormSelection = get_form_selection( 'SourceOperationFormSelection', _(u"Operation search"), 'operation', models.Operation, OperationSelect, 'get-operation', _(u"You should select an operation.")) class OperationSourceSelect(SourceSelect): operation__towns = get_town_field(label=_(u"Operation's town")) operation__operation_type = forms.ChoiceField(label=_(u"Operation type"), choices=[]) operation__year = forms.IntegerField(label=_(u"Operation's year")) def __init__(self, *args, **kwargs): super(OperationSourceSelect, self).__init__(*args, **kwargs) self.fields['operation__operation_type'].choices = \ models.OperationType.get_types() self.fields['operation__operation_type'].help_text = \ models.OperationType.get_help() OperationSourceFormSelection = get_form_selection( 'OperationSourceFormSelection', _(u"Documentation search"), 'pk', models.OperationSource, OperationSourceSelect, 'get-operationsource', _(u"You should select a document.")) ################################################ # Administrative act management for operations # ################################################ class AdministrativeActOpeSelect(TableSelect): operation__towns = get_town_field() act_type = forms.ChoiceField(label=_("Act type"), choices=[]) def __init__(self, *args, **kwargs): super(AdministrativeActOpeSelect, self).__init__(*args, **kwargs) self.fields['act_type'].choices = models.ActType.get_types( dct={'intented_to':'O'}) self.fields['act_type'].help_text = models.ActType.get_help( dct={'intented_to':'O'}) class AdministrativeActOpeFormSelection(forms.Form): form_label = _("Administrative act search") associated_models = {'pk':models.AdministrativeAct} currents = {'pk':models.AdministrativeAct} pk = forms.IntegerField(label="", required=False, widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactop'), AdministrativeActOpeSelect, models.AdministrativeAct, table_cols='TABLE_COLS_OPE'), validators=[valid_id(models.AdministrativeAct)]) def clean(self): cleaned_data = self.cleaned_data if 'pk' not in cleaned_data or not cleaned_data['pk']: raise forms.ValidationError(_(u"You should select an administrative" " act.")) return cleaned_data class AdministrativeActOpeForm(forms.Form): form_label = _("General") associated_models = {'act_type':models.ActType, 'signatory':Person} act_type = forms.ChoiceField(label=_("Act type"), choices=[]) signatory = forms.IntegerField(label=_("Signatory"), widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), associated_model=Person, new=True), validators=[valid_id(Person)], required=False) act_object = forms.CharField(label=_(u"Object"), max_length=200, widget=forms.Textarea, required=False) signature_date = forms.DateField(label=_(u"Signature date"), widget=widgets.JQueryDate) if settings.COUNTRY == 'fr': ref_sra = forms.CharField(label=u"Référence SRA", max_length=15, required=False) def __init__(self, *args, **kwargs): super(AdministrativeActOpeForm, self).__init__(*args, **kwargs) self.fields['act_type'].choices = models.ActType.get_types( dct={'intented_to':'O'}) self.fields['act_type'].help_text = models.ActType.get_help( dct={'intented_to':'O'}) class FinalAdministrativeActDeleteForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this administrative act?") class DocumentGenerationAdminActForm(forms.Form): _associated_model = models.AdministrativeAct document_template = forms.ChoiceField(label=_("Template"), choices=[]) def __init__(self, *args, **kwargs): document_type = 'O' if 'operation' in kwargs: document_type = 'O' if kwargs.pop('operation') else 'F' super(DocumentGenerationAdminActForm, self).__init__(*args, **kwargs) self.fields['document_template'].choices = DocumentTemplate.get_tuples( dct={'associated_object_name': 'archaeological_operations.models.AdministrativeAct', 'acttypes__intented_to':document_type}) def save(self, object_pk): try: c_object = self._associated_model.objects.get(pk=object_pk) except self._associated_model.DoesNotExist: return try: template = DocumentTemplate.objects.get( pk=self.cleaned_data.get('document_template')) except DocumentTemplate.DoesNotExist: return return template.publish(c_object) class GenerateDocForm(forms.Form): form_label = _("Doc generation") doc_generation = forms.ChoiceField(required=False, choices=[], label=_(u"Generate the associated doc?")) def __init__(self, *args, **kwargs): choices = [] if 'choices' in kwargs: choices = kwargs.pop('choices') super(GenerateDocForm, self).__init__(*args, **kwargs) self.fields['doc_generation'].choices = [('', u'-'*9)] + \ [(choice.pk , unicode(choice)) for choice in choices]