PageRenderTime 38ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/dojango/forms/models.py

http://dojango.googlecode.com/
Python | 212 lines | 187 code | 10 blank | 15 comment | 3 complexity | 871b581bb42f3bf3b11f78effb72987a MD5 | raw file
  1. from django.forms import *
  2. from django.forms.models import BaseModelFormSet
  3. from django.forms.models import BaseInlineFormSet
  4. from django.forms.models import ModelChoiceIterator
  5. from django.forms.models import InlineForeignKeyHiddenInput, InlineForeignKeyField
  6. from django.utils.text import capfirst
  7. from formsets import BaseFormSet
  8. from django.db.models import fields
  9. from dojango.forms.fields import *
  10. from dojango.forms.widgets import DojoWidgetMixin, Textarea, Select, SelectMultiple, HiddenInput
  11. __all__ = (
  12. 'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
  13. 'save_instance', 'ModelChoiceField', 'ModelMultipleChoiceField',
  14. )
  15. class ModelChoiceField(DojoFieldMixin, models.ModelChoiceField):
  16. """
  17. Overwritten 'ModelChoiceField' using the 'DojoFieldMixin' functionality.
  18. """
  19. widget = Select
  20. class ModelMultipleChoiceField(DojoFieldMixin, models.ModelMultipleChoiceField):
  21. """
  22. Overwritten 'ModelMultipleChoiceField' using the 'DojoFieldMixin' functonality.
  23. """
  24. widget = SelectMultiple
  25. # Fields #####################################################################
  26. class InlineForeignKeyHiddenInput(DojoWidgetMixin, InlineForeignKeyHiddenInput):
  27. """
  28. Overwritten InlineForeignKeyHiddenInput to use the dojango widget mixin
  29. """
  30. dojo_type = 'dijit.form.TextBox' # otherwise dijit.form.Form can't get its values
  31. class InlineForeignKeyField(DojoFieldMixin, InlineForeignKeyField, Field):
  32. """
  33. Overwritten InlineForeignKeyField to use the dojango field mixin and passing
  34. the dojango InlineForeignKeyHiddenInput as widget.
  35. """
  36. def __init__(self, parent_instance, *args, **kwargs):
  37. self.parent_instance = parent_instance
  38. self.pk_field = kwargs.pop("pk_field", False)
  39. self.to_field = kwargs.pop("to_field", None)
  40. if self.parent_instance is not None:
  41. if self.to_field:
  42. kwargs["initial"] = getattr(self.parent_instance, self.to_field)
  43. else:
  44. kwargs["initial"] = self.parent_instance.pk
  45. kwargs["required"] = False
  46. kwargs["widget"] = InlineForeignKeyHiddenInput
  47. # don't call the the superclass of this one. Use the superclass of the
  48. # normal django InlineForeignKeyField
  49. Field.__init__(self, *args, **kwargs)
  50. # our customized model field => form field map
  51. # here it is defined which form field is used by which model field, when creating a ModelForm
  52. MODEL_TO_FORM_FIELD_MAP = (
  53. # (model_field, form_field, [optional widget])
  54. # the order of these fields is very important for inherited model fields
  55. # e.g. the CharField must be checked at last, because several other
  56. # fields are a subclass of it.
  57. (fields.CommaSeparatedIntegerField, CharField),
  58. (fields.DateTimeField, DateTimeField), # must be in front of the DateField
  59. (fields.DateField, DateField),
  60. (fields.DecimalField, DecimalField),
  61. (fields.EmailField, EmailField),
  62. (fields.FilePathField, FilePathField),
  63. (fields.FloatField, FloatField),
  64. (fields.related.ForeignKey, ModelChoiceField),
  65. (fields.files.ImageField, ImageField),
  66. (fields.files.FileField, FileField),
  67. (fields.IPAddressField, IPAddressField),
  68. (fields.related.ManyToManyField, ModelMultipleChoiceField),
  69. (fields.NullBooleanField, CharField),
  70. (fields.BooleanField, BooleanField),
  71. (fields.PositiveSmallIntegerField, IntegerField),
  72. (fields.PositiveIntegerField, IntegerField),
  73. (fields.SlugField, SlugField),
  74. (fields.SmallIntegerField, IntegerField),
  75. (fields.IntegerField, IntegerField),
  76. (fields.TimeField, TimeField),
  77. (fields.URLField, URLField),
  78. (fields.TextField, CharField, Textarea),
  79. (fields.CharField, CharField),
  80. )
  81. def formfield_function(field, **kwargs):
  82. """
  83. Custom formfield function, so we can inject our own form fields. The
  84. mapping of model fields to form fields is defined in 'MODEL_TO_FORM_FIELD_MAP'.
  85. It uses the default django mapping as fallback, if there is no match in our
  86. custom map.
  87. field -- a model field
  88. """
  89. for field_map in MODEL_TO_FORM_FIELD_MAP:
  90. if isinstance(field, field_map[0]):
  91. defaults = {}
  92. if field.choices:
  93. # the normal django field forms.TypedChoiceField is wired hard
  94. # within the original db/models/fields.py.
  95. # If we use our custom Select widget, we also have to pass in
  96. # some additional validation field attributes.
  97. defaults['widget'] = Select(attrs={
  98. 'extra_field_attrs':{
  99. 'required':not field.blank,
  100. 'help_text':field.help_text,
  101. }
  102. })
  103. elif len(field_map) == 3:
  104. defaults['widget']=field_map[2]
  105. defaults.update(kwargs)
  106. return field.formfield(form_class=field_map[1], **defaults)
  107. # return the default formfield, if there is no equivalent
  108. return field.formfield(**kwargs)
  109. # ModelForms #################################################################
  110. def fields_for_model(*args, **kwargs):
  111. """Changed fields_for_model function, where we use our own formfield_callback"""
  112. kwargs["formfield_callback"] = formfield_function
  113. return models.fields_for_model(*args, **kwargs)
  114. class ModelFormMetaclass(models.ModelFormMetaclass):
  115. """
  116. Overwritten 'ModelFormMetaClass'. We attach our own formfield generation
  117. function.
  118. """
  119. def __new__(cls, name, bases, attrs):
  120. # this is how we can replace standard django form fields with dojo ones
  121. attrs["formfield_callback"] = formfield_function
  122. return super(ModelFormMetaclass, cls).__new__(cls, name, bases, attrs)
  123. class ModelForm(models.ModelForm):
  124. """
  125. Overwritten 'ModelForm' using the metaclass defined above.
  126. """
  127. __metaclass__ = ModelFormMetaclass
  128. def modelform_factory(*args, **kwargs):
  129. """Changed modelform_factory function, where we use our own formfield_callback"""
  130. kwargs["formfield_callback"] = formfield_function
  131. kwargs["form"] = ModelForm
  132. return models.modelform_factory(*args, **kwargs)
  133. # ModelFormSets ##############################################################
  134. class BaseModelFormSet(BaseModelFormSet, BaseFormSet):
  135. def add_fields(self, form, index):
  136. """Overwritten BaseModelFormSet using the dojango BaseFormSet and
  137. the ModelChoiceField.
  138. NOTE: This method was copied from django 1.3 beta 1"""
  139. from django.db.models import AutoField, OneToOneField, ForeignKey
  140. self._pk_field = pk = self.model._meta.pk
  141. def pk_is_not_editable(pk):
  142. return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField))
  143. or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
  144. if pk_is_not_editable(pk) or pk.name not in form.fields:
  145. if form.is_bound:
  146. pk_value = form.instance.pk
  147. else:
  148. try:
  149. if index is not None:
  150. pk_value = self.get_queryset()[index].pk
  151. else:
  152. pk_value = None
  153. except IndexError:
  154. pk_value = None
  155. if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
  156. qs = pk.rel.to._default_manager.get_query_set()
  157. else:
  158. qs = self.model._default_manager.get_query_set()
  159. qs = qs.using(form.instance._state.db)
  160. form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
  161. BaseFormSet.add_fields(self, form, index)
  162. def modelformset_factory(*args, **kwargs):
  163. """Changed modelformset_factory function, where we use our own formfield_callback"""
  164. kwargs["formfield_callback"] = formfield_function
  165. kwargs["formset"] = BaseModelFormSet
  166. return models.modelformset_factory(*args, **kwargs)
  167. # InlineFormSets #############################################################
  168. class BaseInlineFormSet(BaseInlineFormSet, BaseModelFormSet):
  169. """Overwritten BaseInlineFormSet using the dojango InlineForeignKeyFields.
  170. NOTE: This method was copied from django 1.1"""
  171. def add_fields(self, form, index):
  172. super(BaseInlineFormSet, self).add_fields(form, index)
  173. if self._pk_field == self.fk:
  174. form.fields[self._pk_field.name] = InlineForeignKeyField(self.instance, pk_field=True)
  175. else:
  176. kwargs = {
  177. 'label': getattr(form.fields.get(self.fk.name), 'label', capfirst(self.fk.verbose_name))
  178. }
  179. if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name:
  180. kwargs['to_field'] = self.fk.rel.field_name
  181. form.fields[self.fk.name] = InlineForeignKeyField(self.instance, **kwargs)
  182. def inlineformset_factory(*args, **kwargs):
  183. """Changed inlineformset_factory function, where we use our own formfield_callback"""
  184. kwargs["formfield_callback"] = formfield_function
  185. kwargs["formset"] = BaseInlineFormSet
  186. return models.inlineformset_factory(*args, **kwargs)