[Answer]-I have two views that are really similar. How can I "superclass" them?

1👍

This is very easy to do with Class Based Views (CBV).

For example, you may use django.views.generic.FormView, as follows in your views.py:

from django.views import generic

class ClassyFormView(generics.FormView):  # Of course name the view whatever you like
    # Note that I'm not setting any of the specific attributes here
    # As I am planning on overriding this view for each form's specifics

    # This is where you may override methods of the FormView
    def get_context_data(self, *args, **kwargs):
        """ This method allows you to edit the context passed to the template """

        context = super(ClassyFormView, self).get_context_data(*args, **kwargs)  # Get context from FormView

        # Add variables to the context data
        context['message'] = "Hello World!"

        return context

    def form_valid(self, form):
        """ 
        This method is called once the form has been instantiated with 
        POST data and has been validated
        """

        # Do whatever you want after the form is validated
        print(form.cleaned_data['some_field'])

    def form_invalid(self, form):
        # Do something if the form is invalid
        pass

You can then override your custom class, to maintain the specific things it does over FormView, but use the correct form class:

class SearchFormView(ClassyFormView):
    form_class = SearchForm

class PostFormView(ClassyFormView):
    form_class = PostForm

Note that you can (and probably will) also set fields such as prefix, success_url, and template_name, as well as override tons of other methods that may be useful!

Note that if your forms are ModelForms, then you will probably want to use one of the model specific generic form views, such as CreateView or UpdateView. Using these will allow you to access the object that the form is acting on. So, after setting the correct model in the class, your form_valid method may look like this:

def form_valid(self, form):
    self.object = form.save(commit=False)
    # Do stuff here to the object before you save it
    # Such as altering or setting fields
    self.object.some_field = "I'm a string"
    self.object.save()

I can’t explain everything about CBV, or even the class based form views here, so make sure to look at further documentation:

Django Class-Based-View Inspector is a really awesome site that not many people seem to know about! Usually easier than diving into the source code.

Relevant Django docs:


Decided to add a few more details that may be helpful.

The generic views specify defaults for their class attributes, but unless you’re being really generic, it’s usually a good idea to override them. Some explanation on the specific attributes:

  • prefix specifies a prefix for the form. Useful in cases where using multiple forms.
    • Defaults to None.
    • If you require more advanced logic, you can set the prefix by returning it in the get_prefix() method.
  • success_url specifies where the form will redirect to on success. For the model form views, this will default to the model’s get_absolute_url()
    • Can be set by returning success url in get_success_url() method
  • template_name specifies the name of the template that the view will display upon a get request
    • Can be set by returning template name in get_template_name() method.

Configuring URLs for CBV is easy, too. Use the as_view() method as follows:

url(r'^some_url/', SearchFormView.as_view(), name="some-url")
👤Johndt

Leave a comment