# Django 5.2.8 documentation

# Validering av formulär och fält

Formulärvalidering sker när data rensas. Om du vill anpassa den här processen finns det olika platser där du kan göra ändringar, var och en med olika syften. Tre typer av rengöringsmetoder körs under formulärbehandlingen. Dessa körs normalt när du anropar metoden `is_valid()` på ett formulär. Det finns andra saker som också kan utlösa rengöring och validering (åtkomst till attributet `errors` eller direkt anrop av `full_clean()`)), men normalt sett behövs de inte.

I allmänhet kan varje rengöringsmetod höja `ValidationError` om det finns ett problem med de data den bearbetar, och skicka relevant information till `ValidationError`-konstruktören. Se nedan för bästa praxis för att höja `ValidationError`. Om inget `ValidationError` uppstår bör metoden returnera de rensade (normaliserade) data som ett Python-objekt.

Den mesta valideringen kan göras med hjälp av validatorer - hjälpare som kan återanvändas. Validerare är funktioner (eller anropsbara) som tar ett enda argument och ger upphov till `ValidationError` vid ogiltig indata. Validerare körs efter att fältets metoder `to_python` och `validate` har anropats.

Valideringen av ett formulär är uppdelad i flera steg, som kan anpassas eller åsidosättas:

- Metoden `to_python()` på en `Field` är det första steget i varje validering. Den tvingar värdet till en korrekt datatyp och ger upphov till `ValidationError` om det inte är möjligt. Den här metoden tar emot det råa värdet från widgeten och returnerar det konverterade värdet. Till exempel: kommer en `FloatField` att omvandla data till en Python `float` eller ge upphov till ett `ValidationError`.

- Metoden `validate()` för en `Field` hanterar fältspecifik validering som inte lämpar sig för en validerare. Den tar ett värde som har tvingats till en korrekt datatyp och ger upphov till `ValidationError` vid eventuella fel. Den här metoden returnerar ingenting och bör inte ändra värdet. Du bör åsidosätta den för att hantera valideringslogik som du inte kan eller vill lägga in i en validator.

- Metoden `run_validators()` på ett `Field` kör alla fältets validatorer och aggregerar alla fel till ett enda `ValidationError`. Du ska inte behöva åsidosätta den här metoden.

- Metoden `clean()` i en subklass av `Field` är ansvarig för att köra `to_python()`, `validate()` och `run_validators()` i rätt ordning och sprida deras fel. Om någon av metoderna vid något tillfälle ger upphov till `ValidationError`, stoppas valideringen och det felet anges. Denna metod returnerar de rena uppgifterna, som sedan infogas i formulärets ordbok `cleaned_data`.

- Metoden `clean_<fieldname>()` anropas på en formulärunderklass – där `<fieldname>` ersätts med namnet på formulärfältets attribut. Denna metod utför all rengöring som är specifik för det specifika attributet, oberoende av vilken typ av fält det är. Den här metoden får inga parametrar. Du måste leta upp värdet på fältet i `self.cleaned_data` och komma ihåg att det kommer att vara ett Python-objekt vid denna tidpunkt, inte den ursprungliga strängen som skickades in i formuläret (det kommer att vara i `cleaned_data` eftersom den allmänna fältmetoden `clean()` ovan redan har rensat data en gång).

  Om du till exempel vill validera att innehållet i en `CharField` som heter `serialnumber` är unikt, skulle `clean_serialnumber()` vara rätt plats att göra detta. Du behöver inte ett specifikt fält (det är en `CharField`), men du vill ha en formulärfältsspecifik del av valideringen och eventuellt rensa/normera data.

  Returvärdet för den här metoden ersätter det befintliga värdet i `cleaned_data`, så det måste vara fältets värde från `cleaned_data` (även om den här metoden inte ändrade det) eller ett nytt rensat värde.

- Metoden `clean()` i formulärunderklassen kan utföra validering som kräver åtkomst till flera formulärfält. Det är här du kan lägga in kontroller som ”om fält `A` anges, måste fält `B` innehålla en giltig e-postadress”. Den här metoden kan returnera en helt annan ordbok om den vill, som kommer att användas som `cleaned_data`.

  Eftersom fältvalideringsmetoderna har körts när `clean()` anropas, har du också tillgång till formulärets `errors`-attribut som innehåller alla fel som uppstått vid rensning av enskilda fält.

  Note that any errors raised by your `Form.clean()` override will not be associated with any field in particular. They go into a special ”field” (called `__all__`), which you can access via the `non_field_errors()` method if you need to. If you want to attach errors to a specific field in the form, you need to call `add_error()`.

  Observera också att det finns särskilda överväganden när du åsidosätter `clean()`-metoden för en `ModelForm`-underklass. (se ModelForm dokumentation för mer information)

These methods are run in the order given above, one field at a time. That is, for each field in the form (in the order they are declared in the form definition), the `Field.clean()` method (or its override) is run, then `clean_<fieldname>()`. Finally, once those two methods are run for every field, the `Form.clean()` method, or its override, is executed whether or not the previous methods have raised errors.

Exempel på var och en av dessa metoder ges nedan.

Som nämnts kan någon av dessa metoder ge upphov till ett `ValidationError`. För ett fält, om metoden `Field.clean()` ger upphov till ett `ValidationError`, anropas inte någon fältspecifik rengöringsmetod. Rengöringsmetoderna för alla återstående fält körs dock fortfarande.

## Upphävande av `ValidationError`

För att felmeddelanden ska vara flexibla och lätta att åsidosätta bör du beakta följande riktlinjer:

- Tillhandahålla en beskrivande felkod till konstruktören:

      # Good
      ValidationError(_("Invalid value"), code="invalid")

      # Bad
      ValidationError(_("Invalid value"))

- Tvinga inte in variabler i meddelandet; använd platshållare och `params`-argumentet i konstruktören:

      # Good
      ValidationError(
          _("Invalid value: %(value)s"),
          params={"value": "42"},
      )

      # Bad
      ValidationError(_("Invalid value: %s") % value)

- Använd mappningsnycklar i stället för positionsformatering. Detta gör det möjligt att placera variablerna i vilken ordning som helst eller att utelämna dem helt och hållet när meddelandet skrivs om:

      # Good
      ValidationError(
          _("Invalid value: %(value)s"),
          params={"value": "42"},
      )

      # Bad
      ValidationError(
          _("Invalid value: %s"),
          params=("42",),
      )

- Omslut meddelandet med `gettext` för att möjliggöra översättning:

      # Good
      ValidationError(_("Invalid value"))

      # Bad
      ValidationError("Invalid value")

Att sätta ihop allt:

    raise ValidationError(
        _("Invalid value: %(value)s"),
        code="invalid",
        params={"value": "42"},
    )

Det är särskilt viktigt att följa dessa riktlinjer om du skriver återanvändbara formulär, formulärfält och modellfält.

Även om det inte rekommenderas, om du är i slutet av valideringskedjan (dvs. ditt formulär `clean()`-metoden) och du vet att du aldrig kommer att behöva åsidosätta ditt felmeddelande kan du fortfarande välja den mindre verbala:

    ValidationError(_("Invalid value: %s") % value)

Metoderna `Form.errors.as_data()` och `Form.errors.as_json()` har stor nytta av fullt utrustade `ValidationError` (med ett `code`-namn och en `params`-ordbok).

### Upprepa flera fel

Om du upptäcker flera fel under en rensningsmetod och vill signalera dem alla till den som skickar in formuläret, är det möjligt att skicka en lista med fel till konstruktören `ValidationError`.

Som ovan rekommenderas det att skicka en lista över `ValidationError`-instanser med `code` och `params` men en lista med strängar fungerar också:

    # Good
    raise ValidationError(
        [
            ValidationError(_("Error 1"), code="error1"),
            ValidationError(_("Error 2"), code="error2"),
        ]
    )

    # Bad
    raise ValidationError(
        [
            _("Error 1"),
            _("Error 2"),
        ]
    )

## Använda validering i praktiken

I de föregående avsnitten förklarades hur validering fungerar i allmänhet för formulär. Eftersom det ibland kan vara lättare att få saker på plats genom att se varje funktion användas, följer här en serie små exempel som använder var och en av de tidigare funktionerna.

### Använda validerare

Djangos formulär- (och modell-) fält stöder användning av verktygsfunktioner och klasser som kallas validerare. En validator är ett anropbart objekt eller en funktion som tar ett värde och returnerar ingenting om värdet är giltigt eller ger upphov till ett `ValidationError` om inte. Dessa kan skickas till ett fälts konstruktör, via fältets `validators` argument, eller definieras på `Field`-klassen själv med `default_validators`-attributet.

Validatorer kan användas för att validera värden i fältet, låt oss ta en titt på Djangos `SlugField`:

    from django.core import validators
    from django.forms import CharField

    class SlugField(CharField):
        default_validators = [validators.validate_slug]

Som du kan se är `SlugField` en `CharField` med en anpassad validator som validerar att den inskickade texten följer vissa teckenregler. Detta kan också göras på fältdefinitionen så här:

    slug = forms.SlugField()

är likvärdig med:

    slug = forms.CharField(validators=[validators.validate_slug])

Vanliga fall som validering mot ett e-postmeddelande eller ett reguljärt uttryck kan hanteras med hjälp av befintliga valideringsklasser som finns i Django. Till exempel: är `validators.validate_slug` en instans av en `RegexValidator` konstruerad med det första argumentet som är mönstret: `^[-a-zA-Z0-9_]+\Z`. Se avsnittet om Skriva validatorer för att se en lista över vad som redan finns tillgängligt och för ett exempel på hur man skriver en validator.

### Standardrengöring av formulärfält

Låt oss först skapa ett anpassat formulärfält som validerar att dess inmatning är en sträng som innehåller kommaseparerade e-postadresser. Den fullständiga klassen ser ut så här:

    from django import forms
    from django.core.validators import validate_email

    class MultiEmailField(forms.Field):
        def to_python(self, value):
            """Normalize data to a list of strings."""
            # Return an empty list if no input was given.
            if not value:
                return []
            return value.split(",")

        def validate(self, value):
            """Check if value consists only of valid emails."""
            # Use the parent's handling of required fields, etc.
            super().validate(value)
            for email in value:
                validate_email(email)

Varje formulär som använder det här fältet kommer att köra dessa metoder innan något annat kan göras med fältets data. Det här är en rengöring som är specifik för den här typen av fält, oavsett hur det sedan används.

Låt oss skapa en `ContactForm` för att visa hur du använder det här fältet:

    class ContactForm(forms.Form):
        subject = forms.CharField(max_length=100)
        message = forms.CharField()
        sender = forms.EmailField()
        recipients = MultiEmailField()
        cc_myself = forms.BooleanField(required=False)

Använd `MultiEmailField` som vilket annat formulärfält som helst. När metoden `is_valid()` anropas på formuläret kommer metoden `MultiEmailField.clean()` att köras som en del av rengöringsprocessen och den kommer i sin tur att anropa de anpassade metoderna `to_python()` och `validate()`.

### Rengöring av ett specifikt fältattribut

Om vi fortsätter från föregående exempel, anta att vi i vårt `ContactForm` vill se till att fältet `recipients` alltid innehåller adressen `"fred@example.com"`. Det här är validering som är specifik för vårt formulär, så vi vill inte lägga in den i den allmänna klassen `MultiEmailField`. Istället skriver vi en rengöringsmetod som fungerar på fältet `recipients`, så här:

    from django import forms
    from django.core.exceptions import ValidationError

    class ContactForm(forms.Form):
        # Everything as before.
        ...

        def clean_recipients(self):
            data = self.cleaned_data["recipients"]
            if "fred@example.com" not in data:
                raise ValidationError("You have forgotten about Fred!")

            # Always return a value to use as the new cleaned data, even if
            # this method didn't change it.
            return data

### Rengöring och validering av fält som är beroende av varandra

Suppose we add another requirement to our contact form: if the `cc_myself` field is `True`, the `subject` must contain the word `"help"`. We are performing validation on more than one field at a time, so the form’s `clean()` method is a good spot to do this. Notice that we are talking about the `clean()` method on the form here, whereas earlier we were writing a `clean()` method on a field. It’s important to keep the field and form difference clear when working out where to validate things. Fields are single data points, forms are a collection of fields.

När formulärets `clean()`-metod anropas har alla enskilda fältrengöringsmetoder körts (de två föregående avsnitten), så `self.cleaned_data` kommer att fyllas i med alla data som har överlevt hittills. Så du måste också komma ihåg att ta hänsyn till det faktum att de fält du vill validera kanske inte har överlevt de första individuella fältkontrollerna.

Det finns två sätt att rapportera eventuella fel från detta steg. Den vanligaste metoden är förmodligen att visa felet högst upp i formuläret. För att skapa ett sådant fel kan du skapa ett `ValidationError` från `clean()`-metoden. Till exempel:

    from django import forms
    from django.core.exceptions import ValidationError

    class ContactForm(forms.Form):
        # Everything as before.
        ...

        def clean(self):
            cleaned_data = super().clean()
            cc_myself = cleaned_data.get("cc_myself")
            subject = cleaned_data.get("subject")

            if cc_myself and subject:
                # Only do something if both fields are valid so far.
                if "help" not in subject:
                    raise ValidationError(
                        "Did not send for 'help' in the subject despite CC'ing yourself."
                    )

I den här koden visas ett felmeddelande högst upp i formuläret (normalt) som beskriver problemet om valideringsfelet uppstår. Sådana fel är icke-fältfel, som visas i mallen med `{{ form.non_field_errors }}`.

Anropet till `super().clean()` i exempelkoden säkerställer att all valideringslogik i överordnade klasser bibehålls. Om ditt formulär ärver ett annat som inte returnerar en `cleaned_data`-ordbok i sin `clean()`-metod (att göra det är valfritt), tilldela då inte `cleaned_data` till resultatet av `super()`-anropet och använd `self.cleaned_data` istället:

    def clean(self):
        super().clean()
        cc_myself = self.cleaned_data.get("cc_myself")
        ...

Den andra metoden för att rapportera valideringsfel kan innebära att felmeddelandet tilldelas ett av fälten. I det här fallet tilldelar vi ett felmeddelande till både raderna ”subject” och ”cc_myself” i formulärvisningen. Var försiktig när du gör detta i praktiken, eftersom det kan leda till förvirrande formulärutmatning. Vi visar vad som är möjligt här och överlåter åt dig och dina designers att komma fram till vad som fungerar effektivt i just din situation. Vår nya kod (som ersätter det tidigare exemplet) ser ut så här:

    from django import forms

    class ContactForm(forms.Form):
        # Everything as before.
        ...

        def clean(self):
            cleaned_data = super().clean()
            cc_myself = cleaned_data.get("cc_myself")
            subject = cleaned_data.get("subject")

            if cc_myself and subject and "help" not in subject:
                msg = "Must put 'help' in subject when cc'ing yourself."
                self.add_error("cc_myself", msg)
                self.add_error("subject", msg)

Det andra argumentet i `add_error()` kan vara en sträng, eller helst en instans av `ValidationError`. Se Upphävande av ValidationError för mer information. Notera att `add_error()` automatiskt tar bort fältet från `cleaned_data`.