# Django 6.0.7 documentation

# Så här skapar du anpassade modellfält

## Introduktion

Dokumentationen modellreferens förklarar hur man använder Djangos standardfältklasser - `CharField`, `DateField`, etc. För många ändamål är dessa klasser allt du behöver. Ibland kommer dock Django-versionen inte att uppfylla dina exakta krav, eller så vill du använda ett fält som är helt annorlunda än de som levereras med Django.

Djangos inbyggda fälttyper täcker inte alla möjliga databaskolonntyper - bara de vanliga typerna, till exempel `VARCHAR` och `INTEGER`. För mer obskyra kolumntyper, till exempel geografiska polygoner eller till och med användarskapade typer som PostgreSQL anpassade typer, kan du definiera dina egna Django `Field` underklasser.

Alternativt kan du ha ett komplext Python-objekt som på något sätt kan serialiseras för att passa in i en standardkolumntyp i databasen. Detta är ett annat fall där en `Field` subklass kommer att hjälpa dig att använda ditt objekt med dina modeller.

### Vårt exempelobjekt

Att skapa anpassade fält kräver lite uppmärksamhet på detaljer. För att göra det lättare att följa kommer vi att använda ett konsekvent exempel genom hela detta dokument: att omsluta ett Python-objekt som representerar korten i en hand i Bridge. Oroa dig inte, du behöver inte kunna spela Bridge för att följa detta exempel. Du behöver bara veta att 52 kort delas ut jämnt mellan fyra spelare, som traditionellt kallas norr, öst, söder och väst. Vår klass ser ungefär så här ut:

    class Hand:
        """A hand of cards (bridge style)"""

        def __init__(self, north, east, south, west):
            # Input parameters are lists of cards ('Ah', '9s', etc.)
            self.north = north
            self.east = east
            self.south = south
            self.west = west

        # ... (other possibly useful methods omitted) ...

Detta är en vanlig Python-klass, utan något Django-specifikt med den. Vi skulle vilja kunna göra saker som detta i våra modeller (vi antar att `hand`-attributet på modellen är en instans av `Hand`):

    example = MyModel.objects.get(pk=1)
    print(example.hand.north)

    new_hand = Hand(north, east, south, west)
    example.hand = new_hand
    example.save()

Vi tilldelar och hämtar från `hand`-attributet i vår modell precis som alla andra Python-klasser. Tricket är att berätta för Django hur man hanterar att spara och ladda ett sådant objekt.

För att kunna använda klassen `Hand` i våra modeller behöver vi inte ändra den här klassen överhuvudtaget. Detta är idealiskt, eftersom det innebär att du enkelt kan skriva modellstöd för befintliga klasser där du inte kan ändra källkoden.

Observera

Du kanske bara vill dra nytta av anpassade kolumntyper i databasen och hantera data som standard Python-typer i dina modeller; strängar eller flottörer, till exempel. Det här fallet liknar vårt `Hand`-exempel och vi kommer att notera eventuella skillnader när vi går vidare.

## Bakgrundsteori

### Databaslagring

Låt oss börja med modellfält. Om du bryter ner det, ger ett modellfält ett sätt att ta ett normalt Python-objekt - sträng, boolean, `datetime` eller något mer komplext som `Hand` - och konvertera det till och från ett format som är användbart när du hanterar databasen. (Ett sådant format är också användbart för serialisering, men som vi kommer att se senare är det lättare när du har databassidan under kontroll).

Fält i en modell måste på något sätt konverteras så att de passar in i en befintlig kolumntyp i databasen. Olika databaser har olika uppsättningar av giltiga kolumntyper, men regeln är ändå densamma: det är de enda typerna du behöver arbeta med. Allt som du vill lagra i databasen måste passa in i någon av dessa typer.

Normalt skriver du antingen ett Django-fält för att matcha en viss kolumntyp i databasen, eller så behöver du ett sätt att konvertera dina data till exempelvis en sträng.

I vårt exempel med `Hand` kan vi konvertera kortdata till en sträng med 104 tecken genom att sammanfoga alla kort i en förutbestämd ordning - t.ex. alla north-kort först, sedan east-, south- och west-kort. Så `Hand`-objekt kan sparas i text- eller teckenkolumner i databasen.

### Vad gör en fältklass?

Alla Djangos fält (och när vi säger fält i detta dokument menar vi alltid modellfält och inte formulärsfält) är underklasser till `django.db.models.Field`. Det mesta av den information som Django registrerar om ett fält är gemensam för alla fält - namn, hjälptext, unikhet och så vidare. Lagring av all denna information hanteras av `Field`. Vi kommer att gå in på de exakta detaljerna om vad `Field` kan göra senare; för nu räcker det att säga att allt härstammar från `Field` och sedan anpassar viktiga delar av klassens beteende.

Det är viktigt att inse att en Django-fältklass inte är det som lagras i dina modellattribut. Modellattributen innehåller normala Python-objekt. De fältklasser som du definierar i en modell lagras faktiskt i klassen `Meta` när modellklassen skapas (de exakta detaljerna om hur detta görs är oviktiga här). Detta beror på att fältklasserna inte är nödvändiga när du bara skapar och ändrar attribut. Istället tillhandahåller de maskineriet för att konvertera mellan attributvärdet och det som lagras i databasen eller skickas till serializer.

Tänk på detta när du skapar dina egna anpassade fält. Den Django `Field` subklass du skriver tillhandahåller maskineriet för att konvertera mellan dina Python-instanser och databas/serializer-värden på olika sätt (det finns skillnader mellan att lagra ett värde och använda ett värde för uppslagningar, till exempel). Om det här låter lite knepigt, oroa dig inte - det kommer att bli tydligare i exemplen nedan. Kom bara ihåg att du ofta kommer att skapa två klasser när du vill ha ett anpassat fält:

- Den första klassen är det Python-objekt som dina användare kommer att manipulera. De kommer att tilldela det till model-attributet, de kommer att läsa från det för visningsändamål, saker som det. Detta är klassen `Hand` i vårt exempel.

- Den andra klassen är underklassen `Field`. Det här är klassen som vet hur man konverterar den första klassen fram och tillbaka mellan dess permanenta lagringsform och Python-form.

## Skriva en fältunderklass

När du planerar din `Field`-underklass, tänk först på vilken befintlig `Field`-klass ditt nya fält är mest lik. Kan du subklassa ett befintligt Django-fält och spara dig lite arbete? Om inte, bör du subklassa `Field`-klassen, från vilken allt härstammar.

Initialisering av ditt nya fält är en fråga om att separera alla argument som är specifika för ditt fall från de vanliga argumenten och skicka de senare till metoden `__init__()` i `Field` (eller din överordnade klass).

I vårt exempel kommer vi att kalla vårt fält `HandField`. (Det är en bra idé att kalla din `Field` subklass för `<Something>Field`, så att den lätt kan identifieras som en `Field` subklass) Det beter sig inte som något befintligt fält, så vi kommer att subklassa direkt från `Field`:

    from django.db import models

    class HandField(models.Field):
        description = "A hand of cards (bridge style)"

        def __init__(self, *args, **kwargs):
            kwargs["max_length"] = 104
            super().__init__(*args, **kwargs)

Vårt `HandField` accepterar de flesta av standardfältalternativen (se listan nedan), men vi ser till att det har en fast längd, eftersom det bara behöver innehålla 52 kortvärden plus deras färger; totalt 104 tecken.

Observera

Många av Djangos modellfält accepterar alternativ som de inte gör något med. Till exempel kan du skicka både `editable` och `auto_now` till en `django.db.models.DateField` och den kommer att ignorera parametern `editable` (`auto_now` som ställs in innebär `editable=False`). Inget fel uppstår i detta fall.

Detta beteende förenklar fältklasserna, eftersom de inte behöver kontrollera om det finns alternativ som inte är nödvändiga. De skickar alla alternativ till överordnad klass och använder dem inte senare. Det är upp till dig om du vill att dina fält ska vara mer strikta när det gäller de alternativ de väljer, eller om du vill använda det mer tillåtande beteendet hos de aktuella fälten.

Metoden `Field.__init__()` tar emot följande parametrar:

- `verbose_name`

- `namn`

- `primary_key`

- `max_length`

- `unique`

- `blank`

- `null`

- `db_index`

- `rel`: Används för relaterade fält (som `ForeignKey`). Endast för avancerad användning.

- `default`

- `editable`

- `serialize`: Om `False`, kommer fältet inte att serialiseras när modellen skickas till Djangos serializers. Standardvärde är `True`.

- `unique_for_date`

- `unique_for_month`

- `unique_for_year`

- `choices`

- `help_text`

- `db_column`

- `db_tablespace`: Endast för skapande av index, om backend stöder tablespaces. Du kan vanligtvis ignorera detta alternativ.

- `auto_created`: `True` om fältet skapades automatiskt, som för `OneToOneField` som används av modellarv. Endast för avancerad användning.

Alla alternativ utan förklaring i listan ovan har samma betydelse som de har för vanliga Django-fält. Se fältdokumentation för exempel och detaljer.

### Dekonstruktion av fält

Motpolen till att skriva din `__init__()`-metod är att skriva `deconstruct()`-metoden. Den används under modellmigreringar för att tala om för Django hur man tar en instans av ditt nya fält och reducerar det till en serialiserad form - i synnerhet vilka argument som ska skickas till `__init__()` för att återskapa det.

Om du inte har lagt till några extra alternativ utöver det fält du ärvde från, behöver du inte skriva en ny metod `deconstruct()`. Om du däremot ändrar de argument som skickas i `__init__()` (som vi gör i `HandField`), måste du komplettera de värden som skickas.

`deconstruct()` returnerar en tupel med fyra objekt: fältets attributnamn, fältklassens fullständiga importsökväg, de positionella argumenten (som en lista) och nyckelordsargumenten (som en dict). Observera att detta skiljer sig från metoden `deconstruct()` for custom classes som returnerar en tupel av tre saker.

Som författare till ett anpassat fält behöver du inte bry dig om de två första värdena; basklassen `Field` har all kod för att räkna ut fältets attributnamn och importsökväg. Du måste dock bry dig om positions- och nyckelordsargumenten, eftersom det sannolikt är dessa saker du ändrar.

Till exempel, i vår `HandField`-klass ställer vi alltid in max_length i `__init__()`. Metoden `deconstruct()` på basklassen `Field` kommer att se detta och försöka returnera det i nyckelordsargumenten; därför kan vi ta bort det från nyckelordsargumenten för läsbarhetens skull:

    from django.db import models

    class HandField(models.Field):
        def __init__(self, *args, **kwargs):
            kwargs["max_length"] = 104
            super().__init__(*args, **kwargs)

        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            del kwargs["max_length"]
            return name, path, args, kwargs

Om du lägger till ett nytt nyckelordsargument måste du själv skriva kod i `deconstruct()` som lägger in dess värde i `kwargs`. Du bör också utelämna värdet från `kwargs` när det inte är nödvändigt att rekonstruera fältets tillstånd, till exempel när standardvärdet används:

    from django.db import models

    class CommaSepField(models.Field):
        "Implements comma-separated storage of lists"

        def __init__(self, separator=",", *args, **kwargs):
            self.separator = separator
            super().__init__(*args, **kwargs)

        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            # Only include kwarg if it's not the default
            if self.separator != ",":
                kwargs["separator"] = self.separator
            return name, path, args, kwargs

Mer komplexa exempel ligger utanför ramen för detta dokument, men kom ihåg - för varje konfiguration av din Field-instans måste `deconstruct()` returnera argument som du kan skicka till `__init__` för att rekonstruera det tillståndet.

Var extra uppmärksam om du anger nya standardvärden för argument i superklassen `Field`; du vill vara säker på att de alltid inkluderas, snarare än att försvinna om de får det gamla standardvärdet.

Dessutom bör du försöka undvika att returnera värden som positionella argument; när det är möjligt, returnera värden som nyckelordsargument för maximal framtida kompatibilitet. Om du ändrar namn på saker oftare än deras position i konstruktörens argumentlista kanske du föredrar positionella, men kom ihåg att människor kommer att rekonstruera ditt fält från den serialiserade versionen under ett bra tag (kanske år), beroende på hur länge dina migreringar pågår.

Du kan se resultatet av dekonstruktionen genom att titta i migreringar som innehåller fältet, och du kan testa dekonstruktionen i enhetstester genom att dekonstruera och rekonstruera fältet:

    name, path, args, kwargs = my_field_instance.deconstruct()
    new_instance = MyField(*args, **kwargs)
    self.assertEqual(my_field_instance.some_attribute, new_instance.some_attribute)

### Fältattribut påverkar inte databasens kolumndefinition

Du kan åsidosätta `Field.non_db_attrs` för att anpassa attribut för ett fält som inte påverkar en kolumndefinition. Det används under modellmigreringar för att upptäcka no-op `AlterField`-operationer.

Till exempel:

    class CommaSepField(models.Field):
        @property
        def non_db_attrs(self):
            return super().non_db_attrs + ("separator",)

### Ändra basklass för ett anpassat fält

Du kan inte ändra basklassen för ett anpassat fält eftersom Django inte kommer att upptäcka ändringen och göra en migrering för den. Till exempel, om du börjar med:

    class CustomCharField(models.CharField): ...

och sedan bestämmer dig för att du vill använda `TextField` istället, kan du inte ändra underklassen så här:

    class CustomCharField(models.TextField): ...

Istället måste du skapa en ny klass för anpassade fält och uppdatera dina modeller så att de refererar till den:

    class CustomCharField(models.CharField): ...

    class CustomTextField(models.TextField): ...

Som diskuterades i Ta bort fält måste du behålla den ursprungliga klassen `CustomCharField` så länge du har migreringar som refererar till den.

### Dokumentera ditt anpassade fält

Som alltid bör du dokumentera din fälttyp så att användarna vet vad det är. Förutom att tillhandahålla en docstring för den, vilket är användbart för utvecklare, kan du också låta användare av admin-appen se en kort beskrivning av fälttypen via django.contrib.admindocs-applikationen. För att göra detta tillhandahåller du beskrivande text i ett `description` klassattribut för ditt anpassade fält. I exemplet ovan kommer den beskrivning som visas av applikationen `admindocs` för ett `HandField` att vara ”En hand med kort (bridgestil)”.

I visningen `django.contrib.admindocs` interpoleras fältbeskrivningen med `field.__dict__` vilket gör att beskrivningen kan innehålla fältets argument. Till exempel är beskrivningen för `CharField`:

    description = _("String (up to %(max_length)s)")

### Användbara metoder

När du har skapat din `Field`-underklass kan du överväga att åsidosätta några standardmetoder, beroende på ditt fälts beteende. Listan över metoder nedan är i ungefärlig fallande ordning efter betydelse, så börja från toppen.

#### Anpassade databastyper

Säg att du har skapat en PostgreSQL anpassad typ som heter `mytype`. Du kan underklassa `Field` och implementera `db_type()` -metoden, så här:

    from django.db import models

    class MytypeField(models.Field):
        def db_type(self, connection):
            return "mytype"

När du har `MytypeField` kan du använda den i vilken modell som helst, precis som vilken annan `Field`-typ som helst:

    class Person(models.Model):
        name = models.CharField(max_length=80)
        something_else = MytypeField()

Om du strävar efter att bygga en databasagnostisk applikation bör du ta hänsyn till skillnader i databaskolonntyper. Till exempel kallas kolumntypen datum / tid i PostgreSQL `timestamp`, medan samma kolumn i MySQL kallas `datetime`. Du kan hantera detta i en `db_type()`-metod genom att kontrollera attributet `connection.vendor`. Nuvarande inbyggda leverantörsnamn är: `sqlite`, `postgresql`, `mysql` och `oracle`.

Till exempel:

    class MyDateField(models.Field):
        def db_type(self, connection):
            if connection.vendor == "mysql":
                return "datetime"
            else:
                return "timestamp"

Metoderna `db_type()` och `rel_db_type()` anropas av Django när ramverket konstruerar `CREATE TABLE`-satserna för din applikation - det vill säga när du först skapar dina tabeller. Metoderna anropas också när du konstruerar en `WHERE`-sats som innehåller modellfältet - det vill säga när du hämtar data med QuerySet-metoder som `get()`, `filter()` och `exclude()` och har modellfältet som ett argument.

Vissa databaskolumntyper accepterar parametrar, till exempel `CHAR(25)`, där parametern `25` representerar den maximala kolumnlängden. I sådana fall är det mer flexibelt om parametern anges i modellen istället för att vara hårdkodad i metoden `db_type()`. Det skulle till exempel inte vara särskilt meningsfullt att ha ett `CharMaxlength25Field`, som visas här:

    # This is a silly example of hardcoded parameters.
    class CharMaxlength25Field(models.Field):
        def db_type(self, connection):
            return "char(25)"

    # In the model:
    class MyModel(models.Model):
        # ...
        my_field = CharMaxlength25Field()

Ett bättre sätt att göra detta vore att göra parametern specificerbar vid körning, dvs. när klassen instansieras. För att göra det, implementera `Field.__init__()`, så här:

    # This is a much more flexible example.
    class BetterCharField(models.Field):
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length
            super().__init__(*args, **kwargs)

        def db_type(self, connection):
            return "char(%s)" % self.max_length

    # In the model:
    class MyModel(models.Model):
        # ...
        my_field = BetterCharField(25)

Slutligen, om din kolumn kräver en verkligt komplex SQL-konfiguration, returnera `None` från `db_type()`. Detta kommer att leda till att Djangos SQL-skapande kod hoppar över detta fält. Du är sedan ansvarig för att skapa kolumnen i rätt tabell på något annat sätt, men det här ger dig ett sätt att berätta för Django att komma ur vägen.

Metoden `rel_db_type()` anropas av fält som `ForeignKey` och `OneToOneField` som pekar på ett annat fält för att bestämma datatyperna för deras databaskolumner. Om du till exempel har ett `UnsignedAutoField` behöver du också de främmande nycklar som pekar på det fältet för att använda samma datatyp:

    # MySQL unsigned integer (range 0 to 4294967295).
    class UnsignedAutoField(models.AutoField):
        def db_type(self, connection):
            return "integer UNSIGNED AUTO_INCREMENT"

        def rel_db_type(self, connection):
            return "integer UNSIGNED"

#### Konvertera värden till Python-objekt

Om din anpassade klass `Field` hanterar datastrukturer som är mer komplexa än strängar, datum, heltal eller flyttal kan du behöva åsidosätta `from_db_value()` och `to_python()`.

Om det finns för fältunderklassen kommer `from_db_value()` att anropas under alla omständigheter när data laddas från databasen, inklusive i aggregat och `values()`-anrop.

`to_python()` anropas vid deserialisering och under `clean()`-metoden som används från formulär.

Som en allmän regel bör `to_python()` hantera något av följande argument på ett elegant sätt:

- En instans av rätt typ (t.ex. `Hand` i vårt pågående exempel).

- En sträng

- `None` (om fältet tillåter `null=True`)

I vår `HandField`-klass lagrar vi data som ett `VARCHAR`-fält i databasen, så vi måste kunna bearbeta strängar och `None` i `from_db_value()`. I `to_python()` måste vi också hantera `Hand`-instanser:

    import re

    from django.core.exceptions import ValidationError
    from django.db import models
    from django.utils.translation import gettext_lazy as _

    def parse_hand(hand_string):
        """Takes a string of cards and splits into a full hand."""
        p1 = re.compile(".{26}")
        p2 = re.compile("..")
        args = [p2.findall(x) for x in p1.findall(hand_string)]
        if len(args) != 4:
            raise ValidationError(_("Invalid input for a Hand instance"))
        return Hand(*args)

    class HandField(models.Field):
        # ...

        def from_db_value(self, value, expression, connection):
            if value is None:
                return value
            return parse_hand(value)

        def to_python(self, value):
            if isinstance(value, Hand):
                return value

            if value is None:
                return value

            return parse_hand(value)

Lägg märke till att vi alltid returnerar en `Hand`-instans från dessa metoder. Det är Python-objekttypen som vi vill lagra i modellens attribut.

För `to_python()`, om något går fel under värdekonvertering, bör du höja ett `ValidationError` undantag.

#### Konvertera Python-objekt till frågevärden

Eftersom användning av en databas kräver konvertering i båda riktningarna, om du åsidosätter `from_db_value()` måste du också åsidosätta `get_prep_value()` för att konvertera Python-objekt tillbaka till frågevärden.

Till exempel:

    class HandField(models.Field):
        # ...

        def get_prep_value(self, value):
            return "".join(
                ["".join(l) for l in (value.north, value.east, value.south, value.west)]
            )

Varning

Om ditt anpassade fält använder typerna `CHAR`, `VARCHAR` eller `TEXT` för MySQL måste du se till att `get_prep_value()` alltid returnerar en strängtyp. MySQL utför flexibel och oväntad matchning när en fråga utförs på dessa typer och det angivna värdet är ett heltal, vilket kan leda till att frågor inkluderar oväntade objekt i sina resultat. Det här problemet kan inte uppstå om du alltid returnerar en strängtyp från `get_prep_value()`.

#### Konvertering av frågevärden till databasvärden

Vissa datatyper (t.ex. datum) måste vara i ett visst format innan de kan användas av en databas. `get_db_prep_value()` är den metod där dessa konverteringar ska göras. Den specifika anslutning som kommer att användas för frågan skickas som parametern `connection`. Detta gör att du kan använda backend-specifik konverteringslogik om det krävs.

Till exempel använder Django följande metod för sin `BinaryField`:

    def get_db_prep_value(self, value, connection, prepared=False):
        value = super().get_db_prep_value(value, connection, prepared)
        if value is not None:
            return connection.Database.Binary(value)
        return value

Om ditt anpassade fält behöver en särskild konvertering när det sparas som inte är densamma som den konvertering som används för normala frågeparametrar kan du åsidosätta `get_db_prep_save()`.

#### Förbehandling av värden före lagring

Om du vill förbehandla värdet precis innan du sparar det kan du använda `pre_save()`. Till exempel använder Djangos `DateTimeField` den här metoden för att ställa in attributet korrekt i fallet med `auto_now` eller `auto_now_add`.

Om du åsidosätter den här metoden måste du returnera attributets värde i slutet. Du bör också uppdatera modellens attribut om du gör några ändringar i värdet så att kod som har referenser till modellen alltid ser rätt värde.

#### Ange formulärfältet för ett modellfält

För att anpassa det formulärfält som används av `ModelForm` kan du åsidosätta `formfield()`.

Klassen för formulärfältet kan specificeras via argumenten `form_class` och `choices_form_class`; det senare används om fältet har specificerade val, det förra annars. Om dessa argument inte anges kommer `CharField` eller `TypedChoiceField` att användas.

Hela `kwargs`-ordlistan skickas direkt till formulärfältets `__init__()`-metod. Normalt behöver du bara skapa en bra standard för argumentet `form_class` (och kanske `choices_form_class`) och sedan delegera vidare hantering till överordnad klass. Detta kan kräva att du skriver ett anpassat formulärfält (och till och med en formulärwidget). Se formulärdokumentation för information om detta.

Om du vill utesluta fältet från `ModelForm` kan du åsidosätta metoden `formfield()` så att den returnerar `None`.

Fortsätter vi med vårt pågående exempel kan vi skriva `formfield()`-metoden som:

    class HandField(models.Field):
        # ...

        def formfield(self, **kwargs):
            # Exclude the field from the ModelForm when some condition is met.
            some_condition = kwargs.get("some_condition", False)
            if some_condition:
                return None

            # Set up some defaults while letting the caller override them.
            defaults = {"form_class": MyFormField}
            defaults.update(kwargs)
            return super().formfield(**defaults)

Detta förutsätter att vi har importerat fältklassen `MyFormField` (som har sin egen standardwidget). Detta dokument täcker inte detaljerna i att skriva anpassade formulärfält.

#### Emulering av inbyggda fälttyper

Om du har skapat en `db_type()`-metod behöver du inte oroa dig för `get_internal_type()` - den kommer inte att användas särskilt mycket. Ibland är dock databaslagringen av samma typ som något annat fält, och då kan du använda det andra fältets logik för att skapa rätt kolumn.

Till exempel:

    class HandField(models.Field):
        # ...

        def get_internal_type(self):
            return "CharField"

Oavsett vilken databasbackend vi använder kommer detta att innebära att `migrate` och andra SQL-kommandon skapar rätt kolumntyp för lagring av en sträng.

Om `get_internal_type()` returnerar en sträng som inte är känd för Django för den databasbackend du använder - det vill säga, den visas inte i `django.db.backends.<db_name>.base.DatabaseWrapper.data_types` - kommer strängen fortfarande att användas av serialiseraren, men standardmetoden `db_type()` kommer att returnera `None`. Se dokumentationen av `db_type()` för skäl till varför detta kan vara användbart. Att lägga in en beskrivande sträng som typ av fält för serializer är en bra idé om du någonsin kommer att använda serializer-utdata på någon annan plats utanför Django.

#### Konvertering av fältdata för serialisering

Om du vill anpassa hur värdena serialiseras av en serializer kan du åsidosätta `value_to_string()`. Att använda `value_from_object()` är det bästa sättet att få fältets värde före serialisering. Till exempel, eftersom `HandField` ändå använder strängar för sin datalagring, kan vi återanvända en del befintlig konverteringskod:

    class HandField(models.Field):
        # ...

        def value_to_string(self, obj):
            value = self.value_from_object(obj)
            return self.get_prep_value(value)

### Några allmänna råd

Att skriva ett anpassat fält kan vara en knepig process, särskilt om du gör komplexa konverteringar mellan dina Python-typer och dina databas- och serialiseringsformat. Här är ett par tips för att få saker och ting att gå smidigare:

1. Titta på de befintliga Django-fälten (i django/db/models/fields/__init__.py) för inspiration. Försök att hitta ett fält som liknar det du vill ha och utöka det lite, istället för att skapa ett helt nytt fält från grunden.

2. Lägg till en `__str__()`-metod på den klass som du paketerar som ett fält. Det finns många ställen där standardbeteendet för fältkoden är att anropa `str()` på värdet. (I våra exempel i detta dokument skulle `värde` vara en `Hand`-instans, inte en `HandField`). Så om din `__str__()`-metod automatiskt konverterar till strängformen av ditt Python-objekt kan du spara dig mycket arbete.

## Skriva en underklass till `FileField`

Förutom ovanstående metoder har fält som hanterar filer några andra speciella krav som måste tas i beaktande. Majoriteten av den mekanik som tillhandahålls av `FileField`, t.ex. styrning av databaslagring och hämtning, kan förbli oförändrad, vilket gör att underklasser kan hantera utmaningen att stödja en viss typ av fil.

Django tillhandahåller en `File`-klass, som används som en proxy för filens innehåll och operationer. Detta kan underklassificeras för att anpassa hur filen nås och vilka metoder som är tillgängliga. Den lever på `django.db.models.fields.files`, och dess standardbeteende förklaras i fil dokumentation.

När en subklass av `File` har skapats måste den nya subklassen `FileField` få veta att den ska använda den. Detta görs genom att tilldela den nya subklassen `File` det speciella attributet `attr_class` för subklassen `FileField`.

### Några förslag

Utöver ovanstående detaljer finns det några riktlinjer som avsevärt kan förbättra effektiviteten och läsbarheten i fältets kod.

1. Källan till Djangos egen `ImageField` (i django/db/models/fields/files.py) är ett bra exempel på hur man kan underklassa `FileField` för att stödja en viss typ av fil, eftersom den innehåller alla de tekniker som beskrivs ovan.

2. Cacha filattribut när det är möjligt. Eftersom filer kan lagras i fjärrlagringssystem kan det kosta extra tid, eller till och med pengar, att hämta dem, vilket inte alltid är nödvändigt. När en fil har hämtats för att få information om dess innehåll bör så mycket som möjligt av informationen cachas för att minska antalet gånger som filen måste hämtas vid senare anrop för att få samma information.