/django/views/generic/edit.py

https://code.google.com/p/mango-py/ · Python · 242 lines · 126 code · 45 blank · 71 comment · 19 complexity · a28119e666c9ded4838a0183623842f7 MD5 · raw file

  1. from django.forms import models as model_forms
  2. from django.core.exceptions import ImproperlyConfigured
  3. from django.http import HttpResponseRedirect
  4. from django.views.generic.base import TemplateResponseMixin, View
  5. from django.views.generic.detail import (SingleObjectMixin,
  6. SingleObjectTemplateResponseMixin, BaseDetailView)
  7. class FormMixin(object):
  8. """
  9. A mixin that provides a way to show and handle a form in a request.
  10. """
  11. initial = {}
  12. form_class = None
  13. success_url = None
  14. def get_initial(self):
  15. """
  16. Returns the initial data to use for forms on this view.
  17. """
  18. return self.initial
  19. def get_form_class(self):
  20. """
  21. Returns the form class to use in this view
  22. """
  23. return self.form_class
  24. def get_form(self, form_class):
  25. """
  26. Returns an instance of the form to be used in this view.
  27. """
  28. return form_class(**self.get_form_kwargs())
  29. def get_form_kwargs(self):
  30. """
  31. Returns the keyword arguments for instanciating the form.
  32. """
  33. kwargs = {'initial': self.get_initial()}
  34. if self.request.method in ('POST', 'PUT'):
  35. kwargs.update({
  36. 'data': self.request.POST,
  37. 'files': self.request.FILES,
  38. })
  39. return kwargs
  40. def get_context_data(self, **kwargs):
  41. return kwargs
  42. def get_success_url(self):
  43. if self.success_url:
  44. url = self.success_url
  45. else:
  46. raise ImproperlyConfigured(
  47. "No URL to redirect to. Provide a success_url.")
  48. return url
  49. def form_valid(self, form):
  50. return HttpResponseRedirect(self.get_success_url())
  51. def form_invalid(self, form):
  52. return self.render_to_response(self.get_context_data(form=form))
  53. class ModelFormMixin(FormMixin, SingleObjectMixin):
  54. """
  55. A mixin that provides a way to show and handle a modelform in a request.
  56. """
  57. def get_form_class(self):
  58. """
  59. Returns the form class to use in this view
  60. """
  61. if self.form_class:
  62. return self.form_class
  63. else:
  64. if self.model is not None:
  65. # If a model has been explicitly provided, use it
  66. model = self.model
  67. elif hasattr(self, 'object') and self.object is not None:
  68. # If this view is operating on a single object, use
  69. # the class of that object
  70. model = self.object.__class__
  71. else:
  72. # Try to get a queryset and extract the model class
  73. # from that
  74. model = self.get_queryset().model
  75. return model_forms.modelform_factory(model)
  76. def get_form_kwargs(self):
  77. """
  78. Returns the keyword arguments for instanciating the form.
  79. """
  80. kwargs = super(ModelFormMixin, self).get_form_kwargs()
  81. kwargs.update({'instance': self.object})
  82. return kwargs
  83. def get_success_url(self):
  84. if self.success_url:
  85. url = self.success_url % self.object.__dict__
  86. else:
  87. try:
  88. url = self.object.get_absolute_url()
  89. except AttributeError:
  90. raise ImproperlyConfigured(
  91. "No URL to redirect to. Either provide a url or define"
  92. " a get_absolute_url method on the Model.")
  93. return url
  94. def form_valid(self, form):
  95. self.object = form.save()
  96. return super(ModelFormMixin, self).form_valid(form)
  97. def get_context_data(self, **kwargs):
  98. context = kwargs
  99. if self.object:
  100. context['object'] = self.object
  101. context_object_name = self.get_context_object_name(self.object)
  102. if context_object_name:
  103. context[context_object_name] = self.object
  104. return context
  105. class ProcessFormView(View):
  106. """
  107. A mixin that processes a form on POST.
  108. """
  109. def get(self, request, *args, **kwargs):
  110. form_class = self.get_form_class()
  111. form = self.get_form(form_class)
  112. return self.render_to_response(self.get_context_data(form=form))
  113. def post(self, request, *args, **kwargs):
  114. form_class = self.get_form_class()
  115. form = self.get_form(form_class)
  116. if form.is_valid():
  117. return self.form_valid(form)
  118. else:
  119. return self.form_invalid(form)
  120. # PUT is a valid HTTP verb for creating (with a known URL) or editing an
  121. # object, note that browsers only support POST for now.
  122. def put(self, *args, **kwargs):
  123. return self.post(*args, **kwargs)
  124. class BaseFormView(FormMixin, ProcessFormView):
  125. """
  126. A base view for displaying a form
  127. """
  128. class FormView(TemplateResponseMixin, BaseFormView):
  129. """
  130. A view for displaying a form, and rendering a template response.
  131. """
  132. class BaseCreateView(ModelFormMixin, ProcessFormView):
  133. """
  134. Base view for creating an new object instance.
  135. Using this base class requires subclassing to provide a response mixin.
  136. """
  137. def get(self, request, *args, **kwargs):
  138. self.object = None
  139. return super(BaseCreateView, self).get(request, *args, **kwargs)
  140. def post(self, request, *args, **kwargs):
  141. self.object = None
  142. return super(BaseCreateView, self).post(request, *args, **kwargs)
  143. class CreateView(SingleObjectTemplateResponseMixin, BaseCreateView):
  144. """
  145. View for creating an new object instance,
  146. with a response rendered by template.
  147. """
  148. template_name_suffix = '_form'
  149. class BaseUpdateView(ModelFormMixin, ProcessFormView):
  150. """
  151. Base view for updating an existing object.
  152. Using this base class requires subclassing to provide a response mixin.
  153. """
  154. def get(self, request, *args, **kwargs):
  155. self.object = self.get_object()
  156. return super(BaseUpdateView, self).get(request, *args, **kwargs)
  157. def post(self, request, *args, **kwargs):
  158. self.object = self.get_object()
  159. return super(BaseUpdateView, self).post(request, *args, **kwargs)
  160. class UpdateView(SingleObjectTemplateResponseMixin, BaseUpdateView):
  161. """
  162. View for updating an object,
  163. with a response rendered by template..
  164. """
  165. template_name_suffix = '_form'
  166. class DeletionMixin(object):
  167. """
  168. A mixin providing the ability to delete objects
  169. """
  170. success_url = None
  171. def delete(self, request, *args, **kwargs):
  172. self.object = self.get_object()
  173. self.object.delete()
  174. return HttpResponseRedirect(self.get_success_url())
  175. # Add support for browsers which only accept GET and POST for now.
  176. def post(self, *args, **kwargs):
  177. return self.delete(*args, **kwargs)
  178. def get_success_url(self):
  179. if self.success_url:
  180. return self.success_url
  181. else:
  182. raise ImproperlyConfigured(
  183. "No URL to redirect to. Provide a success_url.")
  184. class BaseDeleteView(DeletionMixin, BaseDetailView):
  185. """
  186. Base view for deleting an object.
  187. Using this base class requires subclassing to provide a response mixin.
  188. """
  189. class DeleteView(SingleObjectTemplateResponseMixin, BaseDeleteView):
  190. """
  191. View for deleting an object retrieved with `self.get_object()`,
  192. with a response rendered by template.
  193. """
  194. template_name_suffix = '_confirm_delete'