# Django 6.0.7 documentation

# Sammansatta primärnycklar

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.

## 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

Prior to the introduction of composite primary keys, the single field composing the primary key of a model could be retrieved by introspecting the `primary_key` attribute of its fields:

    >>> 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>

Now that a primary key can be composed of multiple fields the `primary_key` attribute can no longer be relied upon to identify members of the primary key as it will be set to `False` to maintain the invariant that at most one field per model will have this attribute set to `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>
    ]