Hello! In the continuation of a series of articles on Class Based Views (hereinafter referred to as CBV), we proceed to the section on editing objects. In this article we will look at four classes with speaking names: FormView, CreateView, UpdateView, DeleteView.
Part 1 ,
Part 2 ,
Part 3 ,
Part 4Creating and processing a form using CBV
For a number of actions, whether it is registration or authorization on the site, the publication of news, commentary or the addition of goods in the store, it is impossible to do without forms. As a universal tool for creating forms in Django serves FormView class. In the simplest case, to create a workable form, all you need to do is pass it on to a class reference describing the required form:
from django.views.generic.edit import FormView class RegisterForm(FormView): form_class = Register success_url = '/thanks/'
')
or transfer the necessary data directly to the FormView class instance in our urlconf:
url(r'^register/$', FormView.as_view(form_class=Register, success_url='/thanks/')
Note: The example is synthetic and, of course, cannot be used for the registration page in this form.
The form class that needs to be processed is returned by the
get_form_class method. By default, this method returns the
form_class attribute, to which we assigned the class of our form in the example above. We can override this method if we need more complex logic in determining the class of a form.
The
get_success_url method returns the url link to which the transition will be made after successful form processing. By default, this method returns the attribute
success_url .
To specify the form fields for default values, we can pass them directly to the
initial attribute, which is a dictionary, the keys of which must have the names of the required form fields. The value of this attribute is returned by default by the
get_initial method.
It is often necessary to transfer certain data to a form, for example a user object or a predefined list of sections. The
get_form_kwargs method is suitable for this action. When overriding this method, care must be taken not to accidentally overwrite the data passed to the default form. Among them:
def get_form_kwargs(self): """ """ kwargs = {'initial': self.get_initial()} if self.request.method in ('POST', 'PUT'): kwargs.update({ 'data': self.request.POST, 'files': self.request.FILES, }) return kwargs
To avoid losing this data, we must first obtain a dictionary from the parent class, then add the required data to it:
class ProductForm(FormView): def get_form_kwargs(self): kwargs = super(ProductForm, self).get_form_kwargs() kwargs.update({ 'sections': Section.objects.filter(is_active=True) }) return kwargs
To get the class of our form, we can use the
get_form method, which by default returns the form class specified via the
form_class method, with the
get_form_kwargs method dictionary passed to it:
def get_form(self, form_class): return form_class(**self.get_form_kwargs())
When processing the form, if successful, Django calls the
form_valid method of our display. By default, this method redirects the link returned by the
get_success_url method.
In case the incorrect data is
submitted to the form , the
form_invalid method is
called , which by default returns the user back to the form page, passing it an object with a list of validation errors.
class CreatePost(FormView): form_class = PostForm template_name = 'create_post.html' success_url = '/success/' @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): super(CreatePost, self).dispatch(request, *args, **kwargs) def form_valid(self, form): Post.objects.create(**form.cleaned_data) return redirect(self.get_success_url())
Now consider the different areas of application of forms in more detail.
Creating a new instance of an object
Using the example above, we can easily create a new article object, but Django has the tools to create an object with even greater ease, this is the
CreateView class. To use this class, the form submitted to it must inherit from the ModelForm:
from django import forms class NewsForm(forms.ModelForm): class Meta(object): model = News exclude = ('status',)
Now we can pass the object of this form to our display. The display example is almost the same as the previous one:
from django.views.generic.edit import CreateView class CreateNews(CreateView): form_class = NewsForm template_name = 'create_news.html' succes_url = '/success/' def form_valid(self, form): Post.objects.create(**form.cleaned_data) return redirect(self.get_success_url())
If you need to perform more complex actions before saving the model (insert foreign keys, add additional information), then the following example would be a more suitable way to do it (thanks to the
marazmiki user):
def form_valid(self, form):
Note: The definition of the form_valid method may be unnecessary, since CreateView inherits ModelFormMixin, which automatically stores an instance of an object from a form.
For error handling, the
form_invalid method is also used, the functionality of which is similar to that of the FormView class.
Object instance update
The main difference between the UpdateView class and CreateView is the transfer of an instance of a variable object to the
object attribute of this class, otherwise these classes are identical. For editing, we just need to pass to the url the primary key or slug of the variable object:
The description of the form and model for the class CreateView looks the same way.
Deleting an instance of an object
The display logic for deleting an object is somewhat different from the previous classes in this article. For security reasons, deleting an object is only available after sending a post or delete request. In the case of a get request, a page will be displayed confirming the deletion of the object. In the most minimalist version, it can be a form with a submit button and a csrf token:
<form action="" method="post"> {% csrf_token %} <button></button> </form>
The display might look like this:
from django.views.generic.edit import DeleteView class ItemDelete(DeleteView): model = Item template_name = 'item_confirm_delete.html' success_url = '/success/'
Of course, if you need the appropriate checks for user authorization or corresponding rights, you can do this using the decorators for the dispatch method or add your own validation logic:
from django.views.generic.edit import DeleteView class ItemDelete(DeleteView): model = Item template_name = 'item_confirm_delete.html' success_url = '/success/' @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): super(ItemDelete, self).dispatch(request, *args, **kwargs)
In this article, we looked at working with forms and object management, if you have any questions, then I or other readers, I hope, will be able to answer them. Also, please report any errors or inaccuracies found and suggestions for adding information to the article if I missed something. Thank you for reading the article and wish you a happy weekend =)