How do I use CreateView with a ModelForm

DjangoDjango Views

Django Problem Overview


I get an error in my class AuthorCreateForm when I submit my form. NameError self is not defined

How do I use a CreateForm?

I have created a class in my Author.py file

from django.views.generic import TemplateView, ListView, CreateView
from books.models import Author, Publisher, Book
from books.forms import AuthorForm

class AuthorCreateView(CreateView):
    objAuthorForm = AuthorForm(self.request.POST)

    if(objAuthorForm.save()):
        success = "Form saved!"
    else:
        error = "There was an error!"

and I have a html template which submits to /Author/Create

and I have the following line in my urls.py

('^authors/create/$', Author.AuthorCreateView.as_view()),

I render the form at this URL

('^authors/new/$', TemplateView.as_view(template_name="author_new.html")),

I find the class based views confusing, does anyone have a good tutorial on how to use it for CRUD operations?

Thanks

Django Solutions


Solution 1 - Django

What you have is a python error -- self is not defined. self is generally what refers to the class instance itself on class methods.

Anyways, I agree, it's brand spanking new and not as documented. I think looking at the source is absolutely key at this point.

To get comfortable with class based views, I'd start by subclassing django.views.generic.base.View, which implements only a few methods, namely attempting to call a function on the class based on the request method (post, get, head, - look at source).

For example, here's the first step to replace view functions with the new view classes:

class MyClassBasedView(View):
    def get(self, request):
        # behave exactly like old style views
        # except this is called only on get request
        return http.HttpResponse("Get")
    
    def post(self, request):
        return http.HttpResponse("Post")

(r'^foobar/$', MyClassBasedView.as_view())

Back to your specific question:

All TemplateView.as_view() does is render the template - CreateView is a combination of several other classes that handle ModelForms and template rendering (TemplateView).

So, for a very basic example, look to the docs for what class mixins are used by CreateView.

We see it implements TemplateResponseMixin, ModelFormMixin, and ProcessFormView, each containing a list of methods for those classes.


The most basic CreateView

At the most basic level, provide CreateView's ModelFormMixin with the model or custom ModelForm class as documented here.

Your CreateView class would look something like the following

class AuthorCreateView(CreateView):
    form_class = AuthorForm
    template_name = 'author_new.html'
    success_url = 'success'
    
    

With those 3 core attributes set, call it in your URLs.

('^authors/create/$', Author.AuthorCreateView.as_view()),

Render the page and you'll see your ModelForm passed to the template as form, handling the form validation step (passing in request.POST / re-render if invalid), as well as calling form.save() and redirecting to the success_url.


Start overriding the class methods

To customize behavior, start overriding the methods documented for the mixins.

Remember that you simply need to return an HttpResponse from one of these methods just like any regular view function.

Example overriding form_invalid documented in ModelFormMixin:

class AuthorCreateView(CreateView):
    form_class = AuthorForm
    template_name = 'author_new.html'
    success_url = 'success'

    def form_invalid(self, form):
        return http.HttpResponse("form is invalid.. this is just an HttpResponse object")
    

This per-method overriding starts becoming extremely useful as your forms grow more advanced and ultimately lets you build huge forms with a handful of lines of code, overriding only what is necessary.

Say you want to pass your form custom parameters such as the request object (very common if you need access to the user in the form): you merely need to override get_form_kwargs.

class MyFormView(FormView):
    def get_form_kwargs(self):
        # pass "user" keyword argument with the current user to your form
        kwargs = super(MyFormView, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

Class based views are a shining example of smart class usage. It gave me a great intro towards building my own mixins for views and python classes in general. It is saving countless hours.

Wow this got long. To think it started as a mere URL to the docs comment :)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioniJKView Question on Stackoverflow
Solution 1 - DjangoYuji 'Tomita' TomitaView Answer on Stackoverflow