El procesamiento de formularios generalmente tiene 3 rutas:

  • GET inicial (formulario en blanco o rellenado previamente)
  • POST con datos no válidos (normalmente se vuelve a mostrar el formulario con errores)
  • POST con datos válidos (procesa los datos y normalmente redirige)

Implementar esto usted mismo a menudo da como resultado una gran cantidad de código repetitivo repetido (consulte Usar un formulario en una vista). Para ayudar a evitar esto, Django proporciona una colección de vistas genéricas basadas en clases para el procesamiento de formularios.

Formas básicas

Dado un formulario de contacto:

formularios.py

from django import forms

classContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)defsend_email(self):# send email using the self.cleaned_data dictionarypass

La vista se puede construir usando un FormView:

views.py

from myapp.forms import ContactForm
from django.views.generic.edit import FormView

classContactFormView(FormView):
    template_name ='contact.html'
    form_class = ContactForm
    success_url ='/thanks/'defform_valid(self, form):# This method is called when valid form data has been POSTed.# It should return an HttpResponse.
        form.send_email()returnsuper().form_valid(form)

Notas:

  • FormView hereda TemplateResponseMixin asi que template_name se puede utilizar aquí.
  • La implementación predeterminada para form_valid() simplemente redirige a la success_url.

Formas modelo

Las vistas genéricas realmente brillan cuando se trabaja con modelos. Estas vistas genéricas crearán automáticamente una ModelForm, siempre que puedan averiguar qué clase de modelo usar:

  • Si el model attribute se da, se utilizará esa clase de modelo.
  • Si get_object() devuelve un objeto, se utilizará la clase de ese objeto.
  • Si un queryset se proporciona, se utilizará el modelo para ese conjunto de consultas.

Las vistas de formulario de modelo proporcionan una form_valid() implementación que guarda el modelo automáticamente. Puede anular esto si tiene algún requisito especial; consulte los ejemplos a continuación.

Ni siquiera necesita proporcionar un success_url por CreateView o UpdateView ellos usarán get_absolute_url() en el objeto modelo si está disponible.

Si desea utilizar un personalizado ModelForm (por ejemplo, para agregar una validación adicional), establezca form_class en su punto de vista.

Nota

Al especificar una clase de formulario personalizado, aún debe especificar el modelo, aunque el form_class tal vez un ModelForm.

Primero necesitamos agregar get_absolute_url() para nuestro Author clase:

modelos.py

from django.db import models
from django.urls import reverse

classAuthor(models.Model):
    name = models.CharField(max_length=200)defget_absolute_url(self):return reverse('author-detail', kwargs='pk': self.pk)

Entonces podemos usar CreateView y amigos para hacer el trabajo real. Observe cómo solo estamos configurando las vistas genéricas basadas en clases aquí; no tenemos que escribir ninguna lógica nosotros mismos:

views.py

from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from myapp.models import Author

classAuthorCreateView(CreateView):
    model = Author
    fields =['name']classAuthorUpdateView(UpdateView):
    model = Author
    fields =['name']classAuthorDeleteView(DeleteView):
    model = Author
    success_url = reverse_lazy('author-list')

Nota

Tenemos que usar reverse_lazy() en lugar de reverse(), ya que las URL no se cargan cuando se importa el archivo.

los fields attribute funciona de la misma manera que el fields attribute en el interior Meta clase en ModelForm. A menos que defina la clase de formulario de otra manera, el attribute es necesario y la vista generará un ImproperlyConfigured excepción si no lo es.

Si especifica tanto el fields y form_class attributes, un ImproperlyConfigured se planteará una excepción.

Finalmente, conectamos estas nuevas vistas en la URLconf:

urls.py

from django.urls import path
from myapp.views import AuthorCreateView, AuthorDeleteView, AuthorUpdateView

urlpatterns =[# ...
    path('author/add/', AuthorCreateView.as_view(), name='author-add'),
    path('author//', AuthorUpdateView.as_view(), name='author-update'),
    path('author//delete/', AuthorDeleteView.as_view(), name='author-delete'),]

Nota

Estas vistas heredan SingleObjectTemplateResponseMixin que usa template_name_suffix para construir el template_name basado en el modelo.

En este ejemplo:

Si desea tener plantillas separadas para CreateView y UpdateView, puede configurar template_name o template_name_suffix en su clase de vista.

Modelos y request.user

Para rastrear al usuario que creó un objeto usando un CreateView, puedes usar un personalizado ModelForm para hacer esto. Primero, agregue el extranjero key relación con el modelo:

modelos.py

from django.contrib.auth.models import User
from django.db import models

classAuthor(models.Model):
    name = models.CharField(max_length=200)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)# ...

En la vista, asegúrese de no incluir created_by en la lista de campos para editar y anular form_valid() para agregar el usuario:

views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView
from myapp.models import Author

classAuthorCreateView(LoginRequiredMixin, CreateView):
    model = Author
    fields =['name']defform_valid(self, form):
        form.instance.created_by = self.request.user
        returnsuper().form_valid(form)

LoginRequiredMixin evita que los usuarios que no han iniciado sesión accedan al formulario. Si omite eso, deberá manejar usuarios no autorizados en form_valid().

Ejemplo de negociación de contenido

A continuación, se muestra un ejemplo que muestra cómo podría implementar un formulario que funcione con un flujo de trabajo basado en API, así como con POST de formulario ‘normal’:

from django.http import JsonResponse
from django.views.generic.edit import CreateView
from myapp.models import Author

classJsonableResponseMixin:"""
    Mixin to add JSON support to a form.
    Must be used with an object-based FormView (e.g. CreateView)
    """defform_invalid(self, form):
        response =super().form_invalid(form)if self.request.accepts('text/html'):return response
        else:return JsonResponse(form.errors, status=400)defform_valid(self, form):# We make sure to call the parent's form_valid() method because# it might do some processing (in the case of CreateView, it will# call form.save() for example).
        response =super().form_valid(form)if self.request.accepts('text/html'):return response
        else:
            data ='pk': self.object.pk,return JsonResponse(data)classAuthorCreateView(JsonableResponseMixin, CreateView):
    model = Author
    fields =['name']