📜 ⬆️ ⬇️

Django Recipes. Part 1 - AJAX Forms

Hello, habrauzer!

Perhaps I have already started a mid-life crisis , but in the summer I began work on a large Open Source project. However, about it a little later , when the code will not be ashamed . So, I want to share a number of snippets that I had to write in order to comply with the concept of DRY Don't Repeat Youself . Therefore I am going to write several articles.
By the way, you can pay attention to my previous article .

I'll start with the implementation of AJAX.


Just want to make a reservation - not so long ago I found an example on the junga website for implementing ajax form. As it turned out, I did almost the same thing, but I did it myself and I am satisfied =) Below I will give my example and analyze it.
image
')
I ask under the cat.

Speaking about the processing of forms in janga, taking into account the appearance of the django.views.generic module still in release 1.5, one cannot but pay attention to the FormView class. Since all other generic classes for form processing are inherited from it, I chose it as the object of my experiments.

So, let's go:



Backend


The is_valid (self, form) and is_invalid (self, form) methods are responsible for processing the return result if the form meets the requirements of is_valid () and none, respectively. Making our way up the ancestors before FormMixin, we see the following:
def form_valid(self, form): """ If the form is valid, redirect to the supplied URL. """ return HttpResponseRedirect(self.get_success_url()) def form_invalid(self, form): """ If the form is invalid, re-render the context data with the data-filled form and errors. """ return self.render_to_response(self.get_context_data(form=form)) 


In the case of the is_valid () method, only the redirect prevents us. Therefore, we can safely replace this code with the answer we need:
 from django.shortcuts import HttpResponse def form_valid(self, form): return HttpResponse('OK') 

As a result, we get the HTTP 200 code at the output, which expects jquery .

I also allowed myself to peek into the ModelFormMixin class and add a form save before an answer. The result was a hybrid:
  def form_valid(self, form): form.save() return HttpResponse('OK') 


In the case of a form error, the answer is somewhat more complicated - we need to return the error dictionary and display them for the user. However, the task is easily performed using the standard form errors attribute:
 import json from django.http import HttpResponseBadRequest def form_invalid(self, form): errors_dict = json.dumps(dict([(k, [e for e in v]) for k, v in form.errors.items()])) return HttpResponseBadRequest(json.dumps(errors_dict)) 


Ajaxformmixin


So we get the following class:
 from django.views.generic import FormView class AjaxFormMixin(FormView): template_name = 'form_ajax.html' #         ,     =) ,   . def form_valid(self, form): form.save() return HttpResponse('OK') def form_invalid(self, form): errors_dict = json.dumps(dict([(k, [e for e in v]) for k, v in form.errors.items()])) return HttpResponseBadRequest(json.dumps(errors_dict)) 


We now have a class that we can safely inherit, like any other type of Class-based views . The call will look something like this:
 from django.contrib.auth.forms import PasswordChangeForm #  -  ;-) class PasswordChange(AjaxFormMixin): form_class = PasswordChangeForm 


It can be used as a CreateView only with the proviso that we __init __ () method of the parent class FormMixin does not accept the model argument and we will have to do this work ourselves:
 from django.forms.models import modelform_factory class TaskUserAssign(AjaxFormMixin): form_class = modelform_factory(models.TaskRole) 


AjaxUpdateFormMixin


So, we have a base class for handling ajax forms. Why not follow the django-way and create for one more generic “in the image and likeness” for the update. In the same django.views.generic module , we find the UpdateView class and the answer for us — we need the object attribute for our class ... Voila:
 class AjaxUpdateFormMixin(AjaxFormMixin, UpdateView): def get(self, request, *args, **kwargs): self.object = self.get_object() return super(AjaxFormMixin, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.object = self.get_object() return super(AjaxFormMixin, self).post(request, *args, **kwargs) 

Without a doubt, we copy the code, only we inherit everything else from the AjaxFormMixin class that we already have. By the way, this class already has the model attribute, since we inherited it from UpdateView , whose roots go to ModelFormMixin .

As a result, we have a set of classes that support creating, modifying objects and other actions with them (redefine is_valid () as well as / dev / brain and / dev / hands to taste) with ajax answers for free, not prohibited by law inheritance.


PS The purpose of the article was not so much in demonstrating my achievements (although what is there to be cunning), but in the analysis of the process itself. A little later, when my assistant completes the code for the application's muzzle, we will supplement the article with the front-end component code. In the meantime, thank you all for your attention.

Source: https://habr.com/ru/post/241646/


All Articles