diff --git a/AUTHORS b/AUTHORS
index 8cb71c1..fae6f81 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -412,6 +412,7 @@ answer newbie questions, and generally made Django that much better:
     Luciano Ramalho
     Amit Ramon <amit.ramon@gmail.com>
     Philippe Raoult <philippe.raoult@n2nsoft.com>
+    Iván Raskovsky <raskovsky@gmail.com>
     Massimiliano Ravelli <massimiliano.ravelli@gmail.com>
     Brian Ray <http://brianray.chipy.org/>
     Łukasz Rekucki <lrekucki@gmail.com>
diff --git a/django/views/generic/__init__.py b/django/views/generic/__init__.py
index 1a98067..5ef8d97 100644
--- a/django/views/generic/__init__.py
+++ b/django/views/generic/__init__.py
@@ -6,6 +6,10 @@ from django.views.generic.detail import DetailView
 from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
 from django.views.generic.list import ListView
 
+from django.views.generic.formsets import (FormSetsView, ModelFormSetsView,
+                               InlineFormSetsView, EnhancedFormSet,
+                               EnhancedModelFormSet, EnhancedInlineFormSet, )
+
 
 class GenericViewError(Exception):
     """A problem in a generic view."""
diff --git a/django/views/generic/formsets.py b/django/views/generic/formsets.py
new file mode 100644
index 0000000..da9c2ad
--- /dev/null
+++ b/django/views/generic/formsets.py
@@ -0,0 +1,381 @@
+from django.http import HttpResponseRedirect
+from django.core.exceptions import ImproperlyConfigured
+from django.forms.formsets import formset_factory, BaseFormSet, all_valid
+from django.forms.models import (modelformset_factory, inlineformset_factory,
+                                 BaseModelFormSet, BaseInlineFormSet, ModelForm)
+
+from django.views.generic.base import View, TemplateResponseMixin
+from django.views.generic.detail import SingleObjectTemplateResponseMixin
+from django.views.generic.edit import ModelFormMixin
+
+
+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_base_formset(self, **kwargs):
+        """
+        Returns the base formset
+        """
+        new_kwargs = self.get_kwargs()
+        new_kwargs.update(**kwargs)
+        return self.get_factory()(**new_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 EnhancedModelFormSet(EnhancedFormSet):
+    """
+    A base class for generic model formsets
+    """
+    # TODO: provide a hook for formfield_callback
+
+    form_class = ModelForm
+    formset_class = BaseModelFormSet
+    model = None
+    queryset = None
+    fields = None
+    exclude = None
+
+    def get_factory(self):
+        return modelformset_factory
+
+    def get_model(self):
+        if self.model:
+            return self.model
+        else:
+            try:
+                return self.get_form_class().Meta.model
+            except AttributeError:
+                raise ImproperlyConfigured(
+                "No model to create the modelformset. Provide one.")
+
+    def get_queryset(self):
+        return self.queryset
+
+    def get_fields(self):
+        return self.fields
+
+    def get_exclude(self):
+        return self.exclude
+
+    def get_kwargs(self):
+        kwargs = super(EnhancedModelFormSet, self).get_kwargs()
+        kwargs.update({
+            'model': self.get_model(),
+            'fields': self.get_fields(),
+            'exclude': self.get_exclude(),
+        })
+        return kwargs
+
+
+class EnhancedInlineFormSet(EnhancedModelFormSet):
+    """
+    A base class for generic inline formsets
+    """
+
+    fk_name = None
+    formset_class = BaseInlineFormSet
+
+    def get_factory(self):
+        return inlineformset_factory
+
+    def get_fk_name(self):
+        return self.fk_name
+
+    def get_kwargs(self):
+        kwargs = super(EnhancedInlineFormSet, self).get_kwargs()
+        kwargs.update({
+            'fk_name': self.get_fk_name(),
+        })
+        return kwargs
+
+
+class FormSetsMixin(object):
+    """
+    A mixin that provides a way to show and handle formsets
+    """
+
+    formsets = []  # must be a list of BaseGenericFormSet
+    success_url = None
+
+    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
+        """
+        self.formsets_instances = []
+
+        prefixes = {}
+        for enhanced_formset in self.enhanced_formsets_instances:
+            base_formset = enhanced_formset.get_base_formset(
+                **self.get_factory_kwargs())
+
+            # calculate prefix
+            prefix = base_formset.get_default_prefix()
+            prefixes[prefix] = prefixes.get(prefix, 0) + 1
+            if prefixes[prefix] != 1:
+                prefix = "%s-%s" % (prefix, prefixes[prefix])
+
+            self.formsets_instances.append(
+                base_formset(prefix=prefix, **self.get_formsets_kwargs(
+                    enhanced_formset))
+            )
+
+    def get_factory_kwargs(self):
+        """
+        Returns the keyword arguments for the formsets factory
+        """
+        return {}
+
+    def get_formsets_kwargs(self, enhanced_formset):
+        """"
+        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 ModelFormSetsMixin(FormSetsMixin):
+    """
+    A mixin that provides a way to show and handle model formsets
+    """
+
+    def get_formsets_kwargs(self, enhanced_formset):
+        """"
+        Returns the keyword arguments for instanciating the model formsets
+        """
+        kwargs = super(ModelFormSetsMixin, self).get_formsets_kwargs(
+                                                    enhanced_formset)
+        kwargs.update({
+            'queryset': enhanced_formset.get_queryset()
+        })
+        return kwargs
+
+    def formsets_valid(self):
+        # FIXME: beware of m2m
+        for formset in self.formsets_instances:
+            formset.save()
+        return super(ModelFormSetsMixin, self).formsets_valid()
+
+
+class InlineFormSetsMixin(ModelFormSetsMixin, ModelFormMixin):
+    """ 
+    A mixin that provides a way to show and handle a model with it's inline
+    formsets
+    """
+    def get_formsets_kwargs(self, enhanced_formset):
+        """"
+        Returns the keyword arguments for instanciating the inline formsets
+        """
+        kwargs = super(InlineFormSetsMixin, self).get_formsets_kwargs(
+                                                    enhanced_formset)
+        kwargs.update({
+            'instance': self.object
+        })
+        return kwargs
+
+    def get_context_data(self, **kwargs):
+        """
+        Adds the context data from both parents
+        """
+        context_data = ModelFormSetsMixin.get_context_data(self)
+        context_data.update(ModelFormMixin.get_context_data(self, **kwargs))
+        return context_data
+
+    def get_factory_kwargs(self):
+        """
+        Returns the keyword arguments for the formsets factory
+        """
+        return {
+            'parent_model': self.object.__class__,
+        }
+
+    def form_valid(self, form):
+        self.object.save()
+        form.save_m2m()
+        for formset in self.formsets_instances:
+            formset.save()
+
+        return HttpResponseRedirect(self.get_success_url())
+
+    def form_invalid(self, form):
+        return self.render_to_response(self.get_context_data(form=form))
+
+
+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()
+
+    def put(self, request, *args, **kwargs):
+        return self.post(*args, **kwargs)
+
+
+class ProcessInlineFormSetsView(View):
+    """
+    A mixin that processes a model instance and it's inline formsets on POST
+    """
+
+    def get(self, request, *args, **kwargs):
+        # Create or Update
+        try:
+            self.object = self.get_object()
+        except AttributeError:
+            self.object = self.model()
+
+        # ProcessFormView
+        form_class = self.get_form_class()
+        form = self.get_form(form_class)
+
+        # ProcessFormSetsView
+        self.construct_formsets()
+
+        return self.render_to_response(self.get_context_data(form=form))
+
+    def post(self, request, *args, **kwargs):
+        # Create or Update
+        try:
+            self.object = self.get_object()
+        except AttributeError:
+            self.object = self.model()
+
+        # ProcessFormView
+        form_class = self.get_form_class()
+        form = self.get_form(form_class)
+
+        if form.is_valid():
+            self.object = form.save(commit=False)
+
+            # ProcessFormSetsViewV
+            self.construct_formsets()
+
+            if all_valid(self.formsets_instances):
+                return self.form_valid(form)
+        else:
+            # ProcessFormSetsViewV
+            self.construct_formsets()
+        return self.form_invalid(form)
+
+
+    def put(self, request, *args, **kwargs):
+        return self.post(*args, **kwargs)
+
+
+class BaseFormSetsView(FormSetsMixin, ProcessFormSetsView):
+    """
+    A base view for displaying formsets
+    """
+
+
+class BaseModelFormSetsView(ModelFormSetsMixin, ProcessFormSetsView):
+    """
+    A base view for displaying model formsets
+    """
+
+
+class BaseInlineFormSetsView(InlineFormSetsMixin, ProcessInlineFormSetsView):
+    """
+    A base view for displaying a model instance with it's inline formsets
+    """
+
+
+class FormSetsView(TemplateResponseMixin, BaseFormSetsView):
+    """
+    A view for displaying formsets, and rendering a template response
+    """
+
+
+class ModelFormSetsView(TemplateResponseMixin, BaseModelFormSetsView):
+    """
+    A view for displaying model formsets, and rendering a template response
+    """
+
+
+class InlineFormSetsView(SingleObjectTemplateResponseMixin,
+                         BaseInlineFormSetsView):
+    """
+    A view for displaying a model instance with it's inline formsets, and
+    rendering a template response
+    """
+    template_name_suffix = '_form'
+
diff --git a/tests/regressiontests/generic_views/forms.py b/tests/regressiontests/generic_views/forms.py
index 7200947..b6ee715 100644
--- a/tests/regressiontests/generic_views/forms.py
+++ b/tests/regressiontests/generic_views/forms.py
@@ -1,6 +1,9 @@
 from django import forms
+from django.forms.formsets import formset_factory
 
-from regressiontests.generic_views.models import Author
+from django.views.generic import (EnhancedFormSet, EnhancedModelFormSet,
+                                     EnhancedInlineFormSet, )
+from regressiontests.generic_views.models import Author, Article
 
 
 class AuthorForm(forms.ModelForm):
@@ -9,3 +12,29 @@ class AuthorForm(forms.ModelForm):
 
     class Meta:
         model = Author
+
+
+class ArticleForm(forms.ModelForm):
+    class Meta:
+        model = Article
+        exclude = ('author', )
+
+
+class ArticleEnhancedFormSet(EnhancedFormSet):
+    form_class = ArticleForm
+
+
+class AuthorEnhancedFormSet(EnhancedFormSet):
+    form_class = AuthorForm
+
+
+class ArticleEnhancedModelFormSet(EnhancedModelFormSet):
+    model = Article
+
+
+class AuthorEnhancedModelFormSet(EnhancedModelFormSet):
+    model = Author
+
+
+class ArticleEnhancedInlineFormSet(EnhancedInlineFormSet):
+    model = Article
diff --git a/tests/regressiontests/generic_views/formsets.py b/tests/regressiontests/generic_views/formsets.py
new file mode 100644
index 0000000..c9ae954
--- /dev/null
+++ b/tests/regressiontests/generic_views/formsets.py
@@ -0,0 +1,193 @@
+from django.test import TestCase
+from django.core.exceptions import ImproperlyConfigured
+from django.views.generic.formsets import (FormSetsMixin, ModelFormSetsMixin,
+        EnhancedModelFormSet, )
+from regressiontests.generic_views.models import Author, Article
+
+
+class FormSetsViewTests(TestCase):
+    urls = 'regressiontests.generic_views.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-pubdate': u'',
+            'form-1-title': u'',
+            'form-1-pubdate': u'',
+            'form-2-title': u'',
+            'form-2-pubdate': 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-0-slug': u'',
+            'form-2-1-name': u'',
+            'form-2-1-slug': u'',
+            'form-2-2-name': u'',
+            'form-2-2-slug': 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-pubdate': u'2011-01-13',
+            'form-1-title': u'second title',
+            'form-1-pubdate': u'2011-01-13',
+            'form-2-0-name': u'this is my name',
+            'form-2-0-slug': 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-pubdate': u'',
+        })
+        response = self.client.post('/edit/formsets/', self.data)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'ERROR')
+
+
+class ModelFormSetsTests(TestCase):
+    def test_no_model_no_form_class(self):
+        formset = EnhancedModelFormSet()
+        self.assertRaises(ImproperlyConfigured, formset.get_model)
+
+
+class ModelFormSetsViewTests(TestCase):
+    urls = 'regressiontests.generic_views.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-pubdate': u'',
+            'form-1-title': u'',
+            'form-1-pubdate': u'',
+            'form-2-title': u'',
+            'form-2-pubdate': 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/modelformsets/')
+        self.assertEqual(response.status_code, 200)
+
+    def test_empty_post(self):
+        response = self.client.post('/edit/modelformsets/', self.data)
+        self.assertEqual(response.status_code, 302)
+
+    def test_valid(self):
+        self.data.update({
+            'form-0-title': u'first title',
+            'form-0-pubdate': u'2011-01-13',
+            'form-1-title': u'second title',
+            'form-1-pubdate': u'2011-01-13',
+            'form-2-0-name': u'this is my name',
+            'form-2-0-slug': u'this-is-my-name',
+        })
+        response = self.client.post('/edit/modelformsets/', self.data)
+        self.assertEqual(Article.objects.count(), 2)
+        self.assertEqual(Author.objects.count(), 1)
+        self.assertEqual(response.status_code, 302)
+
+    def test_invalid(self):
+        self.data.update({
+            'form-0-title': u'first title',
+            'form-0-pubdate': u'',
+        })
+        response = self.client.post('/edit/modelformsets/', self.data)
+        self.assertEqual(Article.objects.count(), 0)
+        self.assertEqual(Author.objects.count(), 0)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'ERROR')
+
+
+class InlineFormSetsViewTests(TestCase):
+    urls = 'regressiontests.generic_views.urls'
+
+    def setUp(self):
+        self.formsetmgmt = {
+            'article_set-TOTAL_FORMS': u'3',
+            'article_set-INITIAL_FORMS': u'0',
+            'article_set-MAX_NUM_FORMS': u'',
+        }
+        self.formsetdata = {
+            'article_set-0-title': u'title1',
+            'article_set-0-pubdate': u'2011-01-26',
+            'article_set-1-title': u'title2',
+            'article_set-1-pubdate': u'2011-01-26',
+            'article_set-2-title': u'title3',
+            'article_set-2-pubdate': u'2011-01-26',
+        }
+        self.formdata = {
+            'name': u'this is my name',
+            'slug': u'this-is-my-name',
+        }
+
+    def test_get(self):
+        response = self.client.get('/edit/inlineformsets/')
+        self.assertEqual(response.status_code, 200)
+
+    def test_empty_post(self):
+        data = {
+            'article_set-TOTAL_FORMS': u'3',
+            'article_set-INITIAL_FORMS': u'0',
+            'article_set-MAX_NUM_FORMS': u'',
+            'article_set-0-title': u'',
+            'article_set-0-pubdate': u'',
+            'article_set-1-title': u'',
+            'article_set-1-pubdate': u'',
+            'article_set-2-title': u'',
+            'article_set-2-pubdate': u'',
+            'name': u'',
+        }
+        response = self.client.post('/edit/inlineformsets/', data)
+        self.assertEqual(response.status_code, 200)
+
+    def test_valid(self):
+        data = self.formdata
+        data.update(self.formsetdata)
+        data.update(self.formsetmgmt)
+        response = self.client.post('/edit/inlineformsets/', data)
+        self.assertEqual(Article.objects.count(), 3)
+        self.assertEqual(Author.objects.count(), 1)
+        self.assertEqual(response.status_code, 302)
+
+    def test_no_form(self):
+        data = self.formsetdata
+        data.update(self.formsetmgmt)
+        response = self.client.post('/edit/inlineformsets/', data)
+        self.assertEqual(Article.objects.count(), 0)
+        self.assertEqual(Author.objects.count(), 0)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'ERROR')
+
+    def test_no_formset(self):
+        data = self.formdata
+        data.update(self.formsetmgmt)
+        response = self.client.post('/edit/inlineformsets/', data)
+        self.assertEqual(Article.objects.count(), 0)
+        self.assertEqual(Author.objects.count(), 1)
+        self.assertEqual(response.status_code, 302)
diff --git a/tests/regressiontests/generic_views/models.py b/tests/regressiontests/generic_views/models.py
index 5445e24..3a0d9ab 100644
--- a/tests/regressiontests/generic_views/models.py
+++ b/tests/regressiontests/generic_views/models.py
@@ -41,3 +41,9 @@ class Book(models.Model):
 class Page(models.Model):
     content = models.TextField()
     template = models.CharField(max_length=300)
+
+
+class Article(models.Model):
+    title = models.CharField(max_length=100)
+    pubdate = models.DateField()
+    author = models.ForeignKey(Author, blank=True, null=True)
diff --git a/tests/regressiontests/generic_views/templates/authors_articles.html b/tests/regressiontests/generic_views/templates/authors_articles.html
new file mode 100644
index 0000000..7c9eca3
--- /dev/null
+++ b/tests/regressiontests/generic_views/templates/authors_articles.html
@@ -0,0 +1,10 @@
+{% for formset in formsets %}
+    {% if formset.errors %}
+    ERROR
+    {{formset.errors}}
+    {% endif %}
+    {% for form in formset %}
+    {{form.as_p}}
+    {% endfor %}
+    {{formset.management_form}}
+{% endfor %}
diff --git a/tests/regressiontests/generic_views/tests.py b/tests/regressiontests/generic_views/tests.py
index a4010aa..0ab240c 100644
--- a/tests/regressiontests/generic_views/tests.py
+++ b/tests/regressiontests/generic_views/tests.py
@@ -3,3 +3,4 @@ from regressiontests.generic_views.dates import ArchiveIndexViewTests, YearArchi
 from regressiontests.generic_views.detail import DetailViewTest
 from regressiontests.generic_views.edit import ModelFormMixinTests, CreateViewTests, UpdateViewTests, DeleteViewTests
 from regressiontests.generic_views.list import ListViewTests
+from regressiontests.generic_views.formsets import FormSetsViewTests, ModelFormSetsTests, ModelFormSetsViewTests, InlineFormSetsViewTests
diff --git a/tests/regressiontests/generic_views/urls.py b/tests/regressiontests/generic_views/urls.py
index 067c1f6..8ec94cf 100644
--- a/tests/regressiontests/generic_views/urls.py
+++ b/tests/regressiontests/generic_views/urls.py
@@ -208,10 +208,17 @@ urlpatterns = patterns('',
         views.BookDetail.as_view(allow_future=True)),
     (r'^dates/books/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/nopk/$',
         views.BookDetail.as_view()),
-
     (r'^dates/books/(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{1,2})/byslug/(?P<slug>[\w-]+)/$',
         views.BookDetail.as_view()),
 
+    # FormSets
+    (r'^edit/formsets/$',
+        views.AuthorsArticlesView.as_view()),
+    (r'^edit/modelformsets/$',
+        views.AuthorsArticlesModelsView.as_view()),
+    (r'^edit/inlineformsets/$',
+        views.AuthorsInlinesView.as_view()),
+
     # Useful for testing redirects
     (r'^accounts/login/$',  'django.contrib.auth.views.login')
 )
diff --git a/tests/regressiontests/generic_views/views.py b/tests/regressiontests/generic_views/views.py
index 0c8fd49..69ea1ac 100644
--- a/tests/regressiontests/generic_views/views.py
+++ b/tests/regressiontests/generic_views/views.py
@@ -5,8 +5,10 @@ from django.utils.decorators import method_decorator
 from django.views import generic
 
 from regressiontests.generic_views.models import Artist, Author, Book, Page
-from regressiontests.generic_views.forms import AuthorForm
-
+from regressiontests.generic_views.forms import (AuthorForm,
+        ArticleEnhancedFormSet, AuthorEnhancedFormSet,
+        ArticleEnhancedModelFormSet, AuthorEnhancedModelFormSet,
+        ArticleEnhancedInlineFormSet, )
 
 class CustomTemplateView(generic.TemplateView):
     template_name = 'generic_views/about.html'
@@ -177,3 +179,22 @@ class BookDetail(BookConfig, generic.DateDetailView):
 class AuthorGetQuerySetFormView(generic.edit.ModelFormMixin):
     def get_queryset(self):
         return Author.objects.all()
+
+
+class AuthorsArticlesView(generic.FormSetsView):
+    formsets = [ArticleEnhancedFormSet, AuthorEnhancedFormSet, ]
+    template_name = 'authors_articles.html'
+    success_url = '/list/authors/'
+    
+
+class AuthorsArticlesModelsView(generic.ModelFormSetsView):
+    formsets = [ArticleEnhancedModelFormSet, AuthorEnhancedModelFormSet, ]
+    template_name = 'authors_articles.html'
+    success_url = '/list/authors/'
+
+
+class AuthorsInlinesView(generic.InlineFormSetsView):
+    formsets = [ArticleEnhancedInlineFormSet, ]
+    template_name = 'authors_articles.html'
+    success_url = '/list/authors/'
+    model = Author
