# Django 5.2.8 documentation

# Sammansatta primärnycklar

New in Django 5.2.

I Django har varje modell en primärnyckel. Som standard består denna primärnyckel av ett enda fält.

I de flesta fall bör det räcka med en enda primärnyckel. Vid databasdesign är det dock ibland nödvändigt att definiera en primärnyckel som består av flera fält.

För att använda en sammansatt primärnyckel måste du när du definierar en modell ange att attributet `pk` ska vara en `CompositePrimaryKey`:

    class Product(models.Model):
        name = models.CharField(max_length=100)

    class Order(models.Model):
        reference = models.CharField(max_length=20, primary_key=True)

    class OrderLineItem(models.Model):
        pk = models.CompositePrimaryKey("product_id", "order_id")
        product = models.ForeignKey(Product, on_delete=models.CASCADE)
        order = models.ForeignKey(Order, on_delete=models.CASCADE)
        quantity = models.IntegerField()

Detta kommer att instruera Django att skapa en sammansatt primärnyckel (`PRIMARY KEY (product_id, order_id)`) när tabellen skapas.

En sammansatt primärnyckel representeras av en `tupel`:

    >>> product = Product.objects.create(name="apple")
    >>> order = Order.objects.create(reference="A755H")
    >>> item = OrderLineItem.objects.create(product=product, order=order, quantity=1)
    >>> item.pk
    (1, "A755H")

Du kan tilldela en `tuple` till attributet `pk`. Detta ställer in de associerade fältvärdena:

    >>> item = OrderLineItem(pk=(2, "B142C"))
    >>> item.pk
    (2, "B142C")
    >>> item.product_id
    2
    >>> item.order_id
    "B142C"

En sammansatt primärnyckel kan också filtreras med en `tupel`:

    >>> OrderLineItem.objects.filter(pk=(1, "A755H")).count()
    1

Vi arbetar fortfarande med stöd för sammansatta primärnycklar för relationsfält, inklusive `GenericForeignKey`-fält, och Django-admin. Modeller med sammansatta primärnycklar kan för närvarande inte registreras i Django-admin. Du kan förvänta dig att se detta i framtida utgåvor.

## Migrera till en sammansatt primärnyckel

Django stöder inte migrering till eller från en sammansatt primärnyckel efter att tabellen har skapats. Det finns inte heller stöd för att lägga till eller ta bort fält från den sammansatta primärnyckeln.

Om du vill migrera en befintlig tabell från en enda primärnyckel till en sammansatt primärnyckel ska du följa instruktionerna i din databasbackend för att göra det.

När den sammansatta primärnyckeln är på plats lägger du till fältet `CompositePrimaryKey` i din modell. Detta gör att Django kan känna igen och hantera den sammansatta primära nyckeln på lämpligt sätt.

Även om migreringsåtgärder (t.ex. `AddField`, `AlterField`) på primärnyckelfält inte stöds, kommer `makemigrations` ändå att upptäcka ändringar.

För att undvika fel rekommenderas att sådana migreringar görs med `--fake`.

Alternativt kan `SeparateDatabaseAndState` användas för att utföra backend-specifika migreringar och Django-genererade migreringar i en enda operation.

## Sammansatta primärnycklar och relationer

Relationsfält, inklusive generiska relationer har inte stöd för sammansatta primärnycklar.

Till exempel, med modellen `OrderLineItem` stöds inte följande:

    class Foo(models.Model):
        item = models.ForeignKey(OrderLineItem, on_delete=models.CASCADE)

Eftersom `ForeignKey` för närvarande inte kan referera till modeller med sammansatta primärnycklar.

För att komma runt denna begränsning kan `ForeignObject` användas som ett alternativ:

    class Foo(models.Model):
        item_order_id = models.CharField(max_length=20)
        item_product_id = models.IntegerField()
        item = models.ForeignObject(
            OrderLineItem,
            on_delete=models.CASCADE,
            from_fields=("item_order_id", "item_product_id"),
            to_fields=("order_id", "product_id"),
        )

`ForeignObject` är ungefär som `ForeignKey`, förutom att det inte skapar några kolumner (t.ex. `item_id`), främmande nyckelbegränsningar eller index i databasen, och argumentet `on_delete` ignoreras.

Varning

`ForeignObject` är ett internt API. Detta innebär att det inte omfattas av vår deprecation policy.

## Sammansatta primärnycklar och databasfunktioner

Många databasfunktioner accepterar bara ett enda uttryck.

    MAX("order_id")  -- OK
    MAX("product_id", "order_id")  -- ERROR

I dessa fall ger en sammansatt primärnyckelreferens upphov till ett `ValueError`, eftersom den består av flera kolumnuttryck. Undantag görs för `Count`.

    Max("order_id")  # OK
    Max("pk")  # ValueError
    Count("pk")  # OK

## Sammansatta primärnycklar i formulär

Eftersom en sammansatt primärnyckel är ett virtuellt fält, ett fält som inte representerar en enda databaskolumn, är detta fält uteslutet från ModelForms.

Ta till exempel följande formulär:

    class OrderLineItemForm(forms.ModelForm):
        class Meta:
            model = OrderLineItem
            fields = "__all__"

Det här formuläret har inte något formulärfält `pk` för den sammansatta primärnyckeln:

    >>> OrderLineItemForm()
    <OrderLineItemForm bound=False, valid=Unknown, fields=(product;order;quantity)>

Om du anger det primära sammansatta fältet `pk` som ett formulärfält uppstår ett okänt fält `FieldError`.

Primärnyckelfält är skrivskyddade

Om du ändrar värdet på en primärnyckel i ett befintligt objekt och sedan sparar det, skapas ett nytt objekt vid sidan av det gamla (se `Field.primary_key`).

Detta gäller även för sammansatta primärnycklar. Därför kan det vara bra att ställa in `Field.editable` till `False` på alla primärnyckelfält för att utesluta dem från ModelForms.

## Sammansatta primärnycklar i modellvalidering

Eftersom `pk` bara är ett virtuellt fält har det ingen effekt att inkludera `pk` som ett fältnamn i argumentet `exclude` i `Model.clean_fields()`. För att utesluta de sammansatta primärnyckelfälten från modellvalidering, ange varje fält individuellt. `Model.validate_unique()` kan fortfarande anropas med `exclude={"pk"}` för att hoppa över unikhetskontroller.

## Bygga färdiga applikationer med sammansatt primärnyckel

Före införandet av sammansatta primärnycklar kunde det enskilda fält som utgjorde primärnyckeln för en modell hämtas genom introspektion av attributet `primary key` för dess fält:

    >>> pk_field = None
    >>> for field in Product._meta.get_fields():
    ...     if field.primary_key:
    ...         pk_field = field
    ...         break
    ...
    >>> pk_field
    <django.db.models.fields.AutoField: id>

Nu när en primärnyckel kan bestå av flera fält kan attributet `primary key` inte längre användas för att identifiera medlemmar av primärnyckeln eftersom det kommer att sättas till `False` för att upprätthålla invariansen att högst ett fält per modell kommer att ha detta attribut satt till `True`:

    >>> pk_fields = []
    >>> for field in OrderLineItem._meta.get_fields():
    ...     if field.primary_key:
    ...         pk_fields.append(field)
    ...
    >>> pk_fields
    []

För att bygga applikationskod som korrekt hanterar sammansatta primärnycklar bör attributet `_meta.pk_fields` användas istället:

    >>> Product._meta.pk_fields
    [<django.db.models.fields.AutoField: id>]
    >>> OrderLineItem._meta.pk_fields
    [
        <django.db.models.fields.ForeignKey: product>,
        <django.db.models.fields.ForeignKey: order>
    ]