/dojango/forms/models.py
Python | 212 lines | 187 code | 10 blank | 15 comment | 3 complexity | 871b581bb42f3bf3b11f78effb72987a MD5 | raw file
- from django.forms import *
- from django.forms.models import BaseModelFormSet
- from django.forms.models import BaseInlineFormSet
- from django.forms.models import ModelChoiceIterator
- from django.forms.models import InlineForeignKeyHiddenInput, InlineForeignKeyField
- from django.utils.text import capfirst
- from formsets import BaseFormSet
- from django.db.models import fields
- from dojango.forms.fields import *
- from dojango.forms.widgets import DojoWidgetMixin, Textarea, Select, SelectMultiple, HiddenInput
- __all__ = (
- 'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
- 'save_instance', 'ModelChoiceField', 'ModelMultipleChoiceField',
- )
-
- class ModelChoiceField(DojoFieldMixin, models.ModelChoiceField):
- """
- Overwritten 'ModelChoiceField' using the 'DojoFieldMixin' functionality.
- """
- widget = Select
- class ModelMultipleChoiceField(DojoFieldMixin, models.ModelMultipleChoiceField):
- """
- Overwritten 'ModelMultipleChoiceField' using the 'DojoFieldMixin' functonality.
- """
- widget = SelectMultiple
- # Fields #####################################################################
- class InlineForeignKeyHiddenInput(DojoWidgetMixin, InlineForeignKeyHiddenInput):
- """
- Overwritten InlineForeignKeyHiddenInput to use the dojango widget mixin
- """
- dojo_type = 'dijit.form.TextBox' # otherwise dijit.form.Form can't get its values
- class InlineForeignKeyField(DojoFieldMixin, InlineForeignKeyField, Field):
- """
- Overwritten InlineForeignKeyField to use the dojango field mixin and passing
- the dojango InlineForeignKeyHiddenInput as widget.
- """
- def __init__(self, parent_instance, *args, **kwargs):
- self.parent_instance = parent_instance
- self.pk_field = kwargs.pop("pk_field", False)
- self.to_field = kwargs.pop("to_field", None)
- if self.parent_instance is not None:
- if self.to_field:
- kwargs["initial"] = getattr(self.parent_instance, self.to_field)
- else:
- kwargs["initial"] = self.parent_instance.pk
- kwargs["required"] = False
- kwargs["widget"] = InlineForeignKeyHiddenInput
- # don't call the the superclass of this one. Use the superclass of the
- # normal django InlineForeignKeyField
- Field.__init__(self, *args, **kwargs)
- # our customized model field => form field map
- # here it is defined which form field is used by which model field, when creating a ModelForm
- MODEL_TO_FORM_FIELD_MAP = (
- # (model_field, form_field, [optional widget])
- # the order of these fields is very important for inherited model fields
- # e.g. the CharField must be checked at last, because several other
- # fields are a subclass of it.
- (fields.CommaSeparatedIntegerField, CharField),
- (fields.DateTimeField, DateTimeField), # must be in front of the DateField
- (fields.DateField, DateField),
- (fields.DecimalField, DecimalField),
- (fields.EmailField, EmailField),
- (fields.FilePathField, FilePathField),
- (fields.FloatField, FloatField),
- (fields.related.ForeignKey, ModelChoiceField),
- (fields.files.ImageField, ImageField),
- (fields.files.FileField, FileField),
- (fields.IPAddressField, IPAddressField),
- (fields.related.ManyToManyField, ModelMultipleChoiceField),
- (fields.NullBooleanField, CharField),
- (fields.BooleanField, BooleanField),
- (fields.PositiveSmallIntegerField, IntegerField),
- (fields.PositiveIntegerField, IntegerField),
- (fields.SlugField, SlugField),
- (fields.SmallIntegerField, IntegerField),
- (fields.IntegerField, IntegerField),
- (fields.TimeField, TimeField),
- (fields.URLField, URLField),
- (fields.TextField, CharField, Textarea),
- (fields.CharField, CharField),
- )
- def formfield_function(field, **kwargs):
- """
- Custom formfield function, so we can inject our own form fields. The
- mapping of model fields to form fields is defined in 'MODEL_TO_FORM_FIELD_MAP'.
- It uses the default django mapping as fallback, if there is no match in our
- custom map.
-
- field -- a model field
- """
- for field_map in MODEL_TO_FORM_FIELD_MAP:
- if isinstance(field, field_map[0]):
- defaults = {}
- if field.choices:
- # the normal django field forms.TypedChoiceField is wired hard
- # within the original db/models/fields.py.
- # If we use our custom Select widget, we also have to pass in
- # some additional validation field attributes.
- defaults['widget'] = Select(attrs={
- 'extra_field_attrs':{
- 'required':not field.blank,
- 'help_text':field.help_text,
- }
- })
- elif len(field_map) == 3:
- defaults['widget']=field_map[2]
- defaults.update(kwargs)
- return field.formfield(form_class=field_map[1], **defaults)
- # return the default formfield, if there is no equivalent
- return field.formfield(**kwargs)
- # ModelForms #################################################################
- def fields_for_model(*args, **kwargs):
- """Changed fields_for_model function, where we use our own formfield_callback"""
- kwargs["formfield_callback"] = formfield_function
- return models.fields_for_model(*args, **kwargs)
- class ModelFormMetaclass(models.ModelFormMetaclass):
- """
- Overwritten 'ModelFormMetaClass'. We attach our own formfield generation
- function.
- """
- def __new__(cls, name, bases, attrs):
- # this is how we can replace standard django form fields with dojo ones
- attrs["formfield_callback"] = formfield_function
- return super(ModelFormMetaclass, cls).__new__(cls, name, bases, attrs)
- class ModelForm(models.ModelForm):
- """
- Overwritten 'ModelForm' using the metaclass defined above.
- """
- __metaclass__ = ModelFormMetaclass
- def modelform_factory(*args, **kwargs):
- """Changed modelform_factory function, where we use our own formfield_callback"""
- kwargs["formfield_callback"] = formfield_function
- kwargs["form"] = ModelForm
- return models.modelform_factory(*args, **kwargs)
- # ModelFormSets ##############################################################
- class BaseModelFormSet(BaseModelFormSet, BaseFormSet):
-
- def add_fields(self, form, index):
- """Overwritten BaseModelFormSet using the dojango BaseFormSet and
- the ModelChoiceField.
- NOTE: This method was copied from django 1.3 beta 1"""
- from django.db.models import AutoField, OneToOneField, ForeignKey
- self._pk_field = pk = self.model._meta.pk
- def pk_is_not_editable(pk):
- return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField))
- or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
- if pk_is_not_editable(pk) or pk.name not in form.fields:
- if form.is_bound:
- pk_value = form.instance.pk
- else:
- try:
- if index is not None:
- pk_value = self.get_queryset()[index].pk
- else:
- pk_value = None
- except IndexError:
- pk_value = None
- if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
- qs = pk.rel.to._default_manager.get_query_set()
- else:
- qs = self.model._default_manager.get_query_set()
- qs = qs.using(form.instance._state.db)
- form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
- BaseFormSet.add_fields(self, form, index)
- def modelformset_factory(*args, **kwargs):
- """Changed modelformset_factory function, where we use our own formfield_callback"""
- kwargs["formfield_callback"] = formfield_function
- kwargs["formset"] = BaseModelFormSet
- return models.modelformset_factory(*args, **kwargs)
- # InlineFormSets #############################################################
- class BaseInlineFormSet(BaseInlineFormSet, BaseModelFormSet):
- """Overwritten BaseInlineFormSet using the dojango InlineForeignKeyFields.
- NOTE: This method was copied from django 1.1"""
- def add_fields(self, form, index):
- super(BaseInlineFormSet, self).add_fields(form, index)
- if self._pk_field == self.fk:
- form.fields[self._pk_field.name] = InlineForeignKeyField(self.instance, pk_field=True)
- else:
- kwargs = {
- 'label': getattr(form.fields.get(self.fk.name), 'label', capfirst(self.fk.verbose_name))
- }
- if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name:
- kwargs['to_field'] = self.fk.rel.field_name
- form.fields[self.fk.name] = InlineForeignKeyField(self.instance, **kwargs)
-
- def inlineformset_factory(*args, **kwargs):
- """Changed inlineformset_factory function, where we use our own formfield_callback"""
- kwargs["formfield_callback"] = formfield_function
- kwargs["formset"] = BaseInlineFormSet
- return models.inlineformset_factory(*args, **kwargs)