Skip to content

Commit

Permalink
added FormSetsView
Browse files Browse the repository at this point in the history
  • Loading branch information
rasca committed Jan 13, 2011
1 parent e6e7afa commit ae8f3a0
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 0 deletions.
18 changes: 18 additions & 0 deletions enhanced_cbv/tests/forms.py
@@ -0,0 +1,18 @@
from django import forms
from django.forms.formsets import formset_factory

from enhanced_cbv.views.edit import EnhancedFormSet


class ArticleForm(forms.Form):
title = forms.CharField()
pub_date = forms.DateField(required=True)

class AuthorForm(forms.Form):
name = forms.CharField()

class ArticleEnhancedFormSet(EnhancedFormSet):
form_class = ArticleForm

class AuthorEnhancedFormSet(EnhancedFormSet):
form_class = AuthorForm
9 changes: 9 additions & 0 deletions enhanced_cbv/tests/templates/authors_articles.html
@@ -0,0 +1,9 @@
{% for formset in formsets %}
{% if formset.errors %}
ERROR
{% endif %}
{% for form in formset %}
{{form.as_p}}
{% endfor %}
{{formset.management_form}}
{% endfor %}
1 change: 1 addition & 0 deletions enhanced_cbv/tests/templates/dummy.html
@@ -0,0 +1 @@
Dummy
4 changes: 4 additions & 0 deletions enhanced_cbv/tests/test_settings.py
Expand Up @@ -7,6 +7,10 @@
'enhanced_cbv.tests',
)

ROOT_URLCONF = 'enhanced_cbv.tests.urls'

DEBUG_PROPAGATE_EXCEPTIONS = True

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
Expand Down
53 changes: 53 additions & 0 deletions enhanced_cbv/tests/tests.py
@@ -1,2 +1,55 @@
from django.test import TestCase

from enhanced_cbv.views.edit import FormSetsMixin

class FormSetsViewTests(TestCase):
urls = 'enhanced_cbv.tests.urls'

def setUp(self):
self.data = {
'form-TOTAL_FORMS': u'3',
'form-INITIAL_FORMS': u'0',
'form-MAX_NUM_FORMS': u'',
'form-0-title': u'',
'form-0-pub_date': u'',
'form-1-title': u'',
'form-1-pub_date': u'',
'form-2-title': u'',
'form-2-pub_date': u'',

'form-2-TOTAL_FORMS': u'3',
'form-2-INITIAL_FORMS': u'0',
'form-2-MAX_NUM_FORMS': u'',
'form-2-0-name': u'',
'form-2-1-name': u'',
'form-2-2-name': u'',
}

def test_get(self):
response = self.client.get('/edit/formsets/')
self.assertEqual(response.status_code, 200)

def test_empty_post(self):
response = self.client.post('/edit/formsets/', self.data)
self.assertEqual(response.status_code, 302)

def test_valid(self):
self.data.update({
'form-0-title': u'first title',
'form-0-pub_date': u'2011-01-13',
'form-1-title': u'second title',
'form-1-pub_date': u'2011-01-13',
'form-2-0-name': u'this is my name',
})
response = self.client.post('/edit/formsets/', self.data)
self.assertEqual(response.status_code, 302)

def test_invalid(self):
self.data.update({
'form-0-title': u'first title',
'form-0-pub_date': u'',
})
response = self.client.post('/edit/formsets/', self.data)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'ERROR')

11 changes: 11 additions & 0 deletions enhanced_cbv/tests/urls.py
@@ -0,0 +1,11 @@
from django.conf.urls.defaults import *

from enhanced_cbv.tests.views import AuthorsArticlesView


urlpatterns = patterns('',

# FormSetsView
(r'^edit/formsets/$',
AuthorsArticlesView.as_view()),
)
10 changes: 10 additions & 0 deletions enhanced_cbv/tests/views.py
@@ -0,0 +1,10 @@
from enhanced_cbv.views import FormSetsView

from enhanced_cbv.tests.forms import (ArticleEnhancedFormSet,
AuthorEnhancedFormSet)


class AuthorsArticlesView(FormSetsView):
formsets = [ArticleEnhancedFormSet, AuthorEnhancedFormSet]
template_name = 'authors_articles.html'
success_url = '/success/'
1 change: 1 addition & 0 deletions enhanced_cbv/views/__init__.py
@@ -0,0 +1 @@
from edit import FormSetsView
149 changes: 149 additions & 0 deletions enhanced_cbv/views/edit.py
@@ -0,0 +1,149 @@
from django.forms.formsets import formset_factory, BaseFormSet, all_valid
from django.http import HttpResponseRedirect

from django.views.generic.base import View, TemplateResponseMixin


class EnhancedFormSet(object):
"""
A base class for generic formsets
"""

form_class = None
formset_class = BaseFormSet

# formset_factory kwargs
extra = 3
can_order = False
can_delete = False
max_num = None

def get_formset(self, prefix=None, **kwargs):
"""
Returns the instantiated formset
"""
formset = self.get_factory()(**self.get_kwargs())
return formset(prefix=prefix, **kwargs)

def get_factory(self):
"""
Returns the factory used to construct the formsets
"""
return formset_factory

def get_form_class(self):
return self.form_class

def get_formset_class(self):
return self.formset_class

def get_kwargs(self):
return {'form': self.get_form_class(),
'formset': self.get_formset_class(),
'extra': self.extra,
'can_order': self.can_order,
'can_delete': self.can_delete,
'max_num': self.max_num, }


class FormSetsMixin(object):
"""
A mixin that provides a way to show and handle formsets
"""

# must be a list of BaseGenericFormSet
formsets = []

def __init__(self, *args, **kwargs):
self.instantiate_enhanced_formsets()

def instantiate_enhanced_formsets(self):
"""
Instantiates the enhanced formsets
"""
self.enhanced_formsets_instances = []
for formset in self.formsets:
enhanced_formset_instance = formset()
self.enhanced_formsets_instances.append(enhanced_formset_instance)

def construct_formsets(self):
"""
Constructs the formsets
"""
kwargs = self.get_formsets_kwargs()

self.formsets_instances = []

prefixes = {}
for enhanced_formset in self.enhanced_formsets_instances:
prefix = enhanced_formset.get_formset_class().get_default_prefix()
prefixes[prefix] = prefixes.get(prefix, 0) + 1
if prefixes[prefix] != 1:
prefix = "%s-%s" % (prefix, prefixes[prefix])
self.formsets_instances.append(
enhanced_formset.get_formset(prefix=prefix, **kwargs))

def get_formsets_kwargs(self):
""""
Returns the keyword arguments for instanciating the formsets
"""

# default kwargs
kwargs = {}

if self.request.method in ('POST', 'PUT'):
kwargs.update({
'data': self.request.POST,
'files': self.request.FILES,
})
return kwargs

def get_context_data(self, **kwargs):
context_data = {
'formsets': [formset for formset in self.formsets_instances],
}

context_data.update(kwargs)
return context_data

def get_success_url(self):
if self.success_url:
url = self.success_url
else:
raise ImproperlyConfigured(
"No URL to redirect to. Provide a success_url")
return url

def formsets_valid(self):
return HttpResponseRedirect(self.get_success_url())

def formsets_invalid(self):
return self.render_to_response(self.get_context_data())


class ProcessFormSetsView(View):
"""
A mixin that processes formsets on POST
"""
def get(self, request, *args, **kwargs):
self.construct_formsets()
return self.render_to_response(self.get_context_data())

def post(self, request, *args, **kwargs):
self.construct_formsets()
if all_valid(self.formsets_instances):
return self.formsets_valid()
else:
return self.formsets_invalid()


class BaseFormSetsView(FormSetsMixin, ProcessFormSetsView):
"""
A base view for displaying formsets
"""


class FormSetsView(TemplateResponseMixin, BaseFormSetsView):
"""
A view for displaying formsets, and rendering a template response
"""

0 comments on commit ae8f3a0

Please sign in to comment.