---
title: "Formulärhantering med klassbaserade vyer"
version: 5.2
locale: sv
source: https://docs.djangoproject.com/sv/5.2/topics/class-based-views/generic-editing/
canonical: https://djangodocs.dev/sv/5.2/topics/class-based-views/generic-editing/
---
# Formulärhantering med klassbaserade vyer

Formulärhantering har i allmänhet 3 vägar:

- Initial GET (blankett eller förifyllt formulär)
- POST med ogiltiga data (vanligtvis visas formuläret på nytt med fel)
- POST med giltiga data (bearbeta data och typiskt omdirigera)

Att implementera detta själv resulterar ofta i en hel del upprepad boilerplate-kod (se [Använda ett formulär i en vy](/sv/5.2/topics/forms/#using-a-form-in-a-view)). För att hjälpa till att undvika detta tillhandahåller Django en samling generiska klassbaserade vyer för formulärbehandling.

## Grundläggande former

Givet ett kontaktformulär:

*`forms.py`*

```python
from django import forms

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

    def send_email(self):
        # send email using the self.cleaned_data dictionary
        pass
```

Vyn kan byggas upp med hjälp av en `FormView`:

*`Vyer.py`*

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

class ContactFormView(FormView):
    template_name = "contact.html"
    form_class = ContactForm
    success_url = "/thanks/"

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        # It should return an HttpResponse.
        form.send_email()
        return super().form_valid(form)
```

Anteckningar:

- FormView ärver [`TemplateResponseMixin`](/sv/5.2/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin) så [`template_name`](/sv/5.2/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) kan användas här.
- Standardimplementeringen för [`form_valid()`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_valid) omdirigerar helt enkelt till [`success_url`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.success_url).

## Modellformer

Generiska vyer lyser verkligen när man arbetar med modeller.  Dessa generiska vyer kommer automatiskt att skapa en [`ModelForm`](/sv/5.2/topics/forms/modelforms/#django.forms.ModelForm), så länge de kan räkna ut vilken modellklass som ska användas:

- Om attributet [`model`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.model) anges kommer den modellklassen att användas.
- Om [`get_object()`](/sv/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_object) returnerar ett objekt, kommer klassen för det objektet att användas.
- Om en [`queryset`](/sv/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.queryset) anges, kommer modellen för den queryset att användas.

Modellformulärsvyer tillhandahåller en [`form_valid()`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid)-implementering som sparar modellen automatiskt.  Du kan åsidosätta detta om du har några speciella krav; se nedan för exempel.

Du behöver inte ens tillhandahålla en `uccess_url` för [`CreateView`](/sv/5.2/ref/class-based-views/generic-editing/#django.views.generic.edit.CreateView) eller [`UpdateView`](/sv/5.2/ref/class-based-views/generic-editing/#django.views.generic.edit.UpdateView) \- de kommer att använda [`get_absolute_url()`](/sv/5.2/ref/models/instances/#django.db.models.Model.get_absolute_url) på modellobjektet om det finns tillgängligt.

Om du vill använda en anpassad [`ModelForm`](/sv/5.2/topics/forms/modelforms/#django.forms.ModelForm) (t.ex. för att lägga till extra validering), ange [`form_class`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class) på din vy.

> **Note**
>
> När du anger en anpassad formulärklass måste du fortfarande ange modellen, även om [`form_class`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class) kan vara en [`ModelForm`](/sv/5.2/topics/forms/modelforms/#django.forms.ModelForm).

Först måste vi lägga till [`get_absolute_url()`](/sv/5.2/ref/models/instances/#django.db.models.Model.get_absolute_url) till vår `Author` klass:

*`modeller.py`*

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

class Author(models.Model):
    name = models.CharField(max_length=200)

    def get_absolute_url(self):
        return reverse("author-detail", kwargs={"pk": self.pk})
```

Sedan kan vi använda [`CreateView`](/sv/5.2/ref/class-based-views/flattened-index/#CreateView) och dess vänner för att göra det faktiska arbetet. Lägg märke till hur vi bara konfigurerar de generiska klassbaserade vyerna här; vi behöver inte skriva någon logik själva:

*`Vyer.py`*

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

class AuthorCreateView(CreateView):
    model = Author
    fields = ["name"]

class AuthorUpdateView(UpdateView):
    model = Author
    fields = ["name"]

class AuthorDeleteView(DeleteView):
    model = Author
    success_url = reverse_lazy("author-list")
```

> **Note**
>
> Vi måste använda [`reverse_lazy()`](/sv/5.2/ref/urlresolvers/#django.urls.reverse_lazy) istället för `reverse()`, eftersom webbadresserna inte laddas när filen importeras.

Attributet `fields` fungerar på samma sätt som attributet `fields` på den inre `Meta` klassen på [`ModelForm`](/sv/5.2/topics/forms/modelforms/#django.forms.ModelForm). Om du inte definierar formulärklassen på ett annat sätt krävs attributet och vyn kommer att ge upphov till ett [`ImproperlyConfigured`](/sv/5.2/ref/exceptions/#django.core.exceptions.ImproperlyConfigured) undantag om det inte är det.

Om du anger både attributen [`fields`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.fields) och [`form_class`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class), kommer ett [`ImproperlyConfigured`](/sv/5.2/ref/exceptions/#django.core.exceptions.ImproperlyConfigured) undantag att uppstå.

Slutligen kopplar vi in dessa nya vyer i URLconf:

*`urls.py`*

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

urlpatterns = [
    # ...
    path("author/add/", AuthorCreateView.as_view(), name="author-add"),
    path("author/<int:pk>/", AuthorUpdateView.as_view(), name="author-update"),
    path("author/<int:pk>/delete/", AuthorDeleteView.as_view(), name="author-delete"),
]
```

> **Note**
>
> Dessa vyer ärver [`SingleObjectTemplateResponseMixin`](/sv/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin) som använder [`template_name_suffix`](/sv/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix) för att konstruera [`template_name`](/sv/5.2/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) baserat på modellen.
>
> I detta exempel:
>
> - [`CreateView`](/sv/5.2/ref/class-based-views/flattened-index/#CreateView) och [`UpdateView`](/sv/5.2/ref/class-based-views/flattened-index/#UpdateView) använder `myapp/author_form.html`
> - [`DeleteView`](/sv/5.2/ref/class-based-views/flattened-index/#DeleteView) använder `myapp/author_confirm_delete.html`
>
> Om du vill ha separata mallar för [`CreateView`](/sv/5.2/ref/class-based-views/flattened-index/#CreateView) och [`UpdateView`](/sv/5.2/ref/class-based-views/flattened-index/#UpdateView) kan du ange antingen [`template_name`](/sv/5.2/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) eller [`template_name_suffix`](/sv/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix) på din vyklass.

## Modeller och `request.user`

För att spåra den användare som skapade ett objekt med hjälp av en [`CreateView`](/sv/5.2/ref/class-based-views/flattened-index/#CreateView) kan du använda en anpassad [`ModelForm`](/sv/5.2/topics/forms/modelforms/#django.forms.ModelForm) för att göra detta. Lägg först till den främmande nyckelrelationen i modellen:

*`modeller.py`*

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

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

    # ...
```

I vyn ska du se till att du inte inkluderar `created_by` i listan över fält som ska redigeras och åsidosätta [`form_valid()`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid) för att lägga till användaren:

*`Vyer.py`*

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

class AuthorCreateView(LoginRequiredMixin, CreateView):
    model = Author
    fields = ["name"]

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)
```

[`LoginRequiredMixin`](/sv/5.2/topics/auth/default/#django.contrib.auth.mixins.LoginRequiredMixin) hindrar användare som inte är inloggade från att komma åt formuläret. Om du utelämnar det måste du hantera obehöriga användare i [`form_valid()`](/sv/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid).

## Exempel på förhandling om innehåll

Här är ett exempel som visar hur du kan gå tillväga för att implementera ett formulär som fungerar med ett API-baserat arbetsflöde såväl som ”vanliga” formulärposts:

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

class JsonableResponseMixin:
    """
    Mixin to add JSON support to a form.
    Must be used with an object-based FormView (e.g. CreateView)
    """

    def form_invalid(self, form):
        response = super().form_invalid(form)
        if self.request.accepts("text/html"):
            return response
        else:
            return JsonResponse(form.errors, status=400)

    def form_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)

class AuthorCreateView(JsonableResponseMixin, CreateView):
    model = Author
    fields = ["name"]
```

I exemplet ovan antas att om klienten har stöd för `text/html`, så kommer de att föredra det. Detta kanske dock inte alltid är sant. Vid begäran om en `.css`-fil kommer många webbläsare att skicka rubriken `Accept: text/css,*/*;q=0.1`, vilket indikerar att de föredrar CSS, men allt annat går bra. Detta innebär att `request.accepts("text/html")` kommer att vara `True`.

För att bestämma rätt format, med hänsyn till klientens preferenser, använd [`django.http.HttpRequest.get_preferred_type()`](/sv/5.2/ref/request-response/#django.http.HttpRequest.get_preferred_type):

```
class JsonableResponseMixin:
    """
    Mixin to add JSON support to a form.
    Must be used with an object-based FormView (e.g. CreateView).
    """

    accepted_media_types = ["text/html", "application/json"]

    def dispatch(self, request, *args, **kwargs):
        if request.get_preferred_type(self.accepted_media_types) is None:
            # No format in common.
            return HttpResponse(
                status_code=406, headers={"Accept": ",".join(self.accepted_media_types)}
            )

        return super().dispatch(request, *args, **kwargs)

    def form_invalid(self, form):
        response = super().form_invalid(form)
        accepted_type = self.request.get_preferred_type(self.accepted_media_types)
        if accepted_type == "text/html":
            return response
        elif accepted_type == "application/json":
            return JsonResponse(form.errors, status=400)

    def form_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)
        accepted_type = self.request.get_preferred_type(self.accepted_media_types)
        if accepted_type == "text/html":
            return response
        elif accepted_type == "application/json":
            data = {
                "pk": self.object.pk,
            }
            return JsonResponse(data)
```

> **Changed in Django 5.2**
>
> Metoden [`HttpRequest.get_preferred_type()`](/sv/5.2/ref/request-response/#django.http.HttpRequest.get_preferred_type) lades till.
