{"title":"Clés primaires composites","version":"5.2","locale":"fr","docname":"topics/composite-primary-key","url":"/fr/5.2/topics/composite-primary-key/","canonical":"https://djangodocs.dev/fr/5.2/topics/composite-primary-key/","summary":"New in Django 5.2 Avec Django, chaque modèle dispose d’une clé primaire. Par défaut, la clé primaire consiste en un champ unique. Dans la plupart des cas, une clé…","html":"<h1>Clés primaires composites<a class=\"heading-anchor\" href=\"#composite-primary-keys\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h1>\n<aside class=\"version-note version-added\" data-version=\"5.2\">\n<p class=\"version-note-title\">New in Django 5.2</p></aside>\n<p>Avec Django, chaque modèle dispose d’une clé primaire. Par défaut, la clé primaire consiste en un champ unique.</p>\n<p>Dans la plupart des cas, une clé primaire sur un seul champ suffira. Toutefois, en conception de bases de données, la définition d’une clé primaire formée de plusieurs champs est parfois nécessaire.</p>\n<p>Pour utiliser une clé primaire composite lors de la définition d’un modèle, définissez l’attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> à une clé <a class=\"reference internal\" href=\"/fr/5.2/ref/models/fields/#django.db.models.CompositePrimaryKey\" title=\"django.db.models.CompositePrimaryKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CompositePrimaryKey</span></code></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Product</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Order</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">reference</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">,</span> <span class=\"n\">primary_key</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">OrderLineItem</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">pk</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CompositePrimaryKey</span><span class=\"p\">(</span><span class=\"s2\">&quot;product_id&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;order_id&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">product</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Product</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n    <span class=\"n\">order</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Order</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n    <span class=\"n\">quantity</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">IntegerField</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>Cela indiquera à Django de créer une clé primaire composite (<code class=\"docutils literal notranslate\"><span class=\"pre\">PRIMARY</span> <span class=\"pre\">KEY</span> <span class=\"pre\">(product_id,</span> <span class=\"pre\">order_id)</span></code>) lors de la création de la table.</p>\n<p>Une clé primaire composite est représentée par un <code class=\"docutils literal notranslate\"><span class=\"pre\">tuple</span></code>:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">product</span> <span class=\"o\">=</span> <span class=\"n\">Product</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">create</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;apple&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">order</span> <span class=\"o\">=</span> <span class=\"n\">Order</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">create</span><span class=\"p\">(</span><span class=\"n\">reference</span><span class=\"o\">=</span><span class=\"s2\">&quot;A755H&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">item</span> <span class=\"o\">=</span> <span class=\"n\">OrderLineItem</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">create</span><span class=\"p\">(</span><span class=\"n\">product</span><span class=\"o\">=</span><span class=\"n\">product</span><span class=\"p\">,</span> <span class=\"n\">order</span><span class=\"o\">=</span><span class=\"n\">order</span><span class=\"p\">,</span> <span class=\"n\">quantity</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">item</span><span class=\"o\">.</span><span class=\"n\">pk</span>\n<span class=\"go\">(1, &quot;A755H&quot;)</span>\n</code></pre></div>\n<p>Vous pouvez attribuer un <code class=\"docutils literal notranslate\"><span class=\"pre\">tuple</span></code> à l’attribut <a class=\"reference internal\" href=\"/fr/5.2/ref/models/instances/#django.db.models.Model.pk\" title=\"django.db.models.Model.pk\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">pk</span></code></a>. Cela va définir les valeurs de champs associés :</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">item</span> <span class=\"o\">=</span> <span class=\"n\">OrderLineItem</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s2\">&quot;B142C&quot;</span><span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">item</span><span class=\"o\">.</span><span class=\"n\">pk</span>\n<span class=\"go\">(2, &quot;B142C&quot;)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">item</span><span class=\"o\">.</span><span class=\"n\">product_id</span>\n<span class=\"go\">2</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">item</span><span class=\"o\">.</span><span class=\"n\">order_id</span>\n<span class=\"go\">&quot;B142C&quot;</span>\n</code></pre></div>\n<p>Une clé primaire composite peut aussi être filtrée par un <code class=\"docutils literal notranslate\"><span class=\"pre\">tuple</span></code>:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">OrderLineItem</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s2\">&quot;A755H&quot;</span><span class=\"p\">))</span><span class=\"o\">.</span><span class=\"n\">count</span><span class=\"p\">()</span>\n<span class=\"go\">1</span>\n</code></pre></div>\n<p>Nous somme toujours en cours de travail pour la prise en charge des clés primaires composites pour les <a class=\"reference internal\" href=\"#cpk-and-relations\"><span class=\"std std-ref\">champs relationnels</span></a>, y compris les champs <a class=\"reference internal\" href=\"/fr/5.2/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericForeignKey\" title=\"django.contrib.contenttypes.fields.GenericForeignKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">GenericForeignKey</span></code></a> et le site d’administration de Django. À ce stade, les modèles avec clé primaire composite ne peuvent pas être inscrits dans l’administration de Django. Nous espérons pouvoir résoudre ces questions dans de prochaines versions.</p>\n<section id=\"migrating-to-a-composite-primary-key\">\n<h2>Migration vers une clé primaire composite<a class=\"heading-anchor\" href=\"#migrating-to-a-composite-primary-key\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django ne prend actuellement pas en charge la migration depuis ou vers une clé primaire composite une fois qu’une table a été créée. Il ne gère pas non plus l’ajout ou la suppression de champs faisant partie de la clé primaire composite.</p>\n<p>Si vous souhaitez faire migrer une table existante à partir d’une clé primaire unique vers une clé primaire composite, suivez les instructions de votre moteur de base de données pour le faire.</p>\n<p>Après que la clé primaire composite est en place, ajoutez le champ <code class=\"docutils literal notranslate\"><span class=\"pre\">CompositePrimaryKey</span></code> à votre modèle. Cela permet à Django de reconnaître et de traiter correctement la clé primaire composite.</p>\n<p>Même si les opérations de migration (par ex. <code class=\"docutils literal notranslate\"><span class=\"pre\">AddField</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">AlterField</span></code>) sur des champs de clé primaire ne sont pas prises en charge, <code class=\"docutils literal notranslate\"><span class=\"pre\">makemigrations</span></code> détecte tout de même les modifications.</p>\n<p>Afin d’éviter les erreurs, il est recommandé d’appliquer de telles migrations avec <code class=\"docutils literal notranslate\"><span class=\"pre\">--fake</span></code>.</p>\n<p>Une autre possibilité est d’utiliser <a class=\"reference internal\" href=\"/fr/5.2/ref/migration-operations/#django.db.migrations.operations.SeparateDatabaseAndState\" title=\"django.db.migrations.operations.SeparateDatabaseAndState\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">SeparateDatabaseAndState</span></code></a> pour exécuter les migrations spécifiques au moteur et les migrations générées par Django dans une seule opération.</p>\n</section>\n<section id=\"composite-primary-keys-and-relations\">\n<span id=\"cpk-and-relations\"></span><h2>Les clés primaires composites et les relations<a class=\"heading-anchor\" href=\"#composite-primary-keys-and-relations\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Les <a class=\"reference internal\" href=\"/fr/5.2/ref/models/fields/#relationship-fields\"><span class=\"std std-ref\">champs relationnels</span></a> ainsi que les <a class=\"reference internal\" href=\"/fr/5.2/ref/contrib/contenttypes/#generic-relations\"><span class=\"std std-ref\">relations génériques</span></a> ne prennent pas en charge les clés primaires composites.</p>\n<p>Par exemple, considérant le modèle <code class=\"docutils literal notranslate\"><span class=\"pre\">OrderLineItem</span></code>, le code suivant n’est pas possible :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Foo</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">item</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">OrderLineItem</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Car <code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code> ne peut actuellement pas faire référence à des modèles avec clé primaire composite.</p>\n<p>Pour contourner cette limite, <code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignObject</span></code> peut être utilisé comme alternative :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Foo</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">item_order_id</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">)</span>\n    <span class=\"n\">item_product_id</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">IntegerField</span><span class=\"p\">()</span>\n    <span class=\"n\">item</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignObject</span><span class=\"p\">(</span>\n        <span class=\"n\">OrderLineItem</span><span class=\"p\">,</span>\n        <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">,</span>\n        <span class=\"n\">from_fields</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"s2\">&quot;item_order_id&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;item_product_id&quot;</span><span class=\"p\">),</span>\n        <span class=\"n\">to_fields</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"s2\">&quot;order_id&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;product_id&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignObject</span></code> ressemble beaucoup à <code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code>, sauf qu’il ne crée pas de colonne (par ex. <code class=\"docutils literal notranslate\"><span class=\"pre\">item_id</span></code>), de contrainte de clé étrangère ni d’index en base de données, et l’argument <code class=\"docutils literal notranslate\"><span class=\"pre\">on_delete</span></code> est ignoré.</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Avertissement</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignObject</span></code> est une API interne. Cela signifie qu’il n’est pas couvert par notre <a class=\"reference internal\" href=\"/fr/5.2/internals/release-process/#internal-release-deprecation-policy\"><span class=\"std std-ref\">politique d’obsolescence</span></a>.</p>\n</aside>\n</section>\n<section id=\"composite-primary-keys-and-database-functions\">\n<span id=\"cpk-and-database-functions\"></span><h2>Les clés primaires composites et les fonctions de base de données<a class=\"heading-anchor\" href=\"#composite-primary-keys-and-database-functions\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Beaucoup de fonctions de base de données n’acceptent qu’une seule expression.</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">MAX</span><span class=\"p\">(</span><span class=\"ss\">&quot;order_id&quot;</span><span class=\"p\">)</span><span class=\"w\">  </span><span class=\"c1\">-- OK</span>\n<span class=\"k\">MAX</span><span class=\"p\">(</span><span class=\"ss\">&quot;product_id&quot;</span><span class=\"p\">,</span><span class=\"w\"> </span><span class=\"ss\">&quot;order_id&quot;</span><span class=\"p\">)</span><span class=\"w\">  </span><span class=\"c1\">-- ERROR</span>\n</code></pre></div>\n<p>Dans ces cas, si on fournit une référence à une clé primaire composite, une erreur <code class=\"docutils literal notranslate\"><span class=\"pre\">ValueError</span></code> sera produite, car cette clé est composée de plusieurs colonnes. Une exception est admise pour <code class=\"docutils literal notranslate\"><span class=\"pre\">Count</span></code>.</p>\n<div class=\"code-block\" data-language=\"python\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"n\">Max</span><span class=\"p\">(</span><span class=\"s2\">&quot;order_id&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># OK</span>\n<span class=\"n\">Max</span><span class=\"p\">(</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># ValueError</span>\n<span class=\"n\">Count</span><span class=\"p\">(</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># OK</span>\n</code></pre></div>\n</section>\n<section id=\"composite-primary-keys-in-forms\">\n<h2>Les clés primaires composites dans les formulaires<a class=\"heading-anchor\" href=\"#composite-primary-keys-in-forms\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Comme une clé primaire composite est un champ virtuel, c’est-à-dire un champ qui ne représente pas une seule colonne de base de données, ce champ est exclu des formulaires <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelForms</span></code>.</p>\n<p>Par exemple, en prenant l’exemple de ce formulaire</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">OrderLineItemForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">ModelForm</span><span class=\"p\">):</span>\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">OrderLineItem</span>\n        <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;__all__&quot;</span>\n</code></pre></div>\n<p>Ce formulaire ne possède pas de champ de formulaire <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> pour la clé primaire composite :</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">OrderLineItemForm</span><span class=\"p\">()</span>\n<span class=\"go\">&lt;OrderLineItemForm bound=False, valid=Unknown, fields=(product;order;quantity)&gt;</span>\n</code></pre></div>\n<p>Si on veut définir la clé primaire composite <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> comme champ de formulaire, une erreur <a class=\"reference internal\" href=\"/fr/5.2/ref/exceptions/#django.core.exceptions.FieldError\" title=\"django.core.exceptions.FieldError\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">FieldError</span></code></a> de champ inconnu est générée.</p>\n<aside class=\"admonition-primary-key-fields-are-read-only admonition\">\n<p class=\"admonition-title\">Les champs de clé primaire sont en lecture seule</p>\n<p>Si vous modifiez la valeur d’une clé primaire d’un objet existant et que vous l’enregistrez, un nouvel objet est créé en parallèle à l’ancien (voir <a class=\"reference internal\" href=\"/fr/5.2/ref/models/fields/#django.db.models.Field.primary_key\" title=\"django.db.models.Field.primary_key\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">Field.primary_key</span></code></a>).</p>\n<p>Ceci se vérifie aussi pour les clés primaires composites. Ainsi, vous pouvez définir <a class=\"reference internal\" href=\"/fr/5.2/ref/models/fields/#django.db.models.Field.editable\" title=\"django.db.models.Field.editable\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">Field.editable</span></code></a> à <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> pour tous les champs de clé primaire afin de les exclure des formulaires <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code>.</p>\n</aside>\n</section>\n<section id=\"composite-primary-keys-in-model-validation\">\n<h2>Les clés primaires composites dans la validation des modèles<a class=\"heading-anchor\" href=\"#composite-primary-keys-in-model-validation\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Comme <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> n’est qu’un champ virtuel, l’inclusion de <code class=\"docutils literal notranslate\"><span class=\"pre\">pk</span></code> comme nom de champ dans l’argument <code class=\"docutils literal notranslate\"><span class=\"pre\">exclude</span></code> de <a class=\"reference internal\" href=\"/fr/5.2/ref/models/instances/#django.db.models.Model.clean_fields\" title=\"django.db.models.Model.clean_fields\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Model.clean_fields()</span></code></a> n’a aucun effet. Pour exclure les champs de clé primaire composite de la <a class=\"reference internal\" href=\"/fr/5.2/ref/models/instances/#validating-objects\"><span class=\"std std-ref\">validation des modèles</span></a>, indiquez chacun des champs concernés individuellement. <a class=\"reference internal\" href=\"/fr/5.2/ref/models/instances/#django.db.models.Model.validate_unique\" title=\"django.db.models.Model.validate_unique\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">Model.validate_unique()</span></code></a> peut tout de même être appelée avec <code class=\"docutils literal notranslate\"><span class=\"pre\">exclude={&quot;pk&quot;}</span></code> pour omettre les contrôles d’unicité.</p>\n</section>\n<section id=\"building-composite-primary-key-ready-applications\">\n<h2>Construction d’applications compatibles avec les clés primaires composites<a class=\"heading-anchor\" href=\"#building-composite-primary-key-ready-applications\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Avant l’introduction des clés primaires composites, le champ unique composant la clé primaire pouvait être consulté en interrogeant l’attribut <a class=\"reference internal\" href=\"/fr/5.2/ref/models/fields/#django.db.models.Field.primary_key\" title=\"django.db.models.Field.primary_key\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">primary_key</span></code></a> de ses champs :</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">pk_field</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">field</span> <span class=\"ow\">in</span> <span class=\"n\">Product</span><span class=\"o\">.</span><span class=\"n\">_meta</span><span class=\"o\">.</span><span class=\"n\">get_fields</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"k\">if</span> <span class=\"n\">field</span><span class=\"o\">.</span><span class=\"n\">primary_key</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"n\">pk_field</span> <span class=\"o\">=</span> <span class=\"n\">field</span>\n<span class=\"gp\">... </span>        <span class=\"k\">break</span>\n<span class=\"gp\">...</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">pk_field</span>\n<span class=\"go\">&lt;django.db.models.fields.AutoField: id&gt;</span>\n</code></pre></div>\n<p>Maintenant qu’une clé primaire peut être composée de plusieurs champs, il n’est plus possible de se fier à l’attribut <a class=\"reference internal\" href=\"/fr/5.2/ref/models/fields/#django.db.models.Field.primary_key\" title=\"django.db.models.Field.primary_key\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">primary_key</span></code></a> pour identifier la composition de la clé primaire, car il vaudra <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> pour maintenir la règle qu’au plus un seul champ par modèle peut avoir cet attribut à <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">pk_fields</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">for</span> <span class=\"n\">field</span> <span class=\"ow\">in</span> <span class=\"n\">OrderLineItem</span><span class=\"o\">.</span><span class=\"n\">_meta</span><span class=\"o\">.</span><span class=\"n\">get_fields</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"k\">if</span> <span class=\"n\">field</span><span class=\"o\">.</span><span class=\"n\">primary_key</span><span class=\"p\">:</span>\n<span class=\"gp\">... </span>        <span class=\"n\">pk_fields</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">field</span><span class=\"p\">)</span>\n<span class=\"gp\">...</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">pk_fields</span>\n<span class=\"go\">[]</span>\n</code></pre></div>\n<p>Si l’on veut construire du code applicatif qui sache gérer correctement les clés primaires composites, l’attribut <a class=\"reference internal\" href=\"/fr/5.2/ref/models/meta/#django.db.models.options.Options.pk_fields\" title=\"django.db.models.options.Options.pk_fields\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">_meta.pk_fields</span></code></a> est maintenant disponible :</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Product</span><span class=\"o\">.</span><span class=\"n\">_meta</span><span class=\"o\">.</span><span class=\"n\">pk_fields</span>\n<span class=\"go\">[&lt;django.db.models.fields.AutoField: id&gt;]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">OrderLineItem</span><span class=\"o\">.</span><span class=\"n\">_meta</span><span class=\"o\">.</span><span class=\"n\">pk_fields</span>\n<span class=\"go\">[</span>\n<span class=\"go\">    &lt;django.db.models.fields.ForeignKey: product&gt;,</span>\n<span class=\"go\">    &lt;django.db.models.fields.ForeignKey: order&gt;</span>\n<span class=\"go\">]</span>\n</code></pre></div>\n</section>","rootId":"composite-primary-keys","toc":[{"title":"Migration vers une clé primaire composite","anchor":"migrating-to-a-composite-primary-key","children":[]},{"title":"Les clés primaires composites et les relations","anchor":"composite-primary-keys-and-relations","children":[]},{"title":"Les clés primaires composites et les fonctions de base de données","anchor":"composite-primary-keys-and-database-functions","children":[]},{"title":"Les clés primaires composites dans les formulaires","anchor":"composite-primary-keys-in-forms","children":[]},{"title":"Les clés primaires composites dans la validation des modèles","anchor":"composite-primary-keys-in-model-validation","children":[]},{"title":"Construction d’applications compatibles avec les clés primaires composites","anchor":"building-composite-primary-key-ready-applications","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"Utilisation de Django","url":"/fr/5.2/topics/"}],"prev":{"docname":"topics/conditional-view-processing","title":"Traitement conditionnel de vue","url":"/fr/5.2/topics/conditional-view-processing/"},"next":{"docname":"topics/signing","title":"Signatures cryptographiques","url":"/fr/5.2/topics/signing/"},"formats":{"html":"/fr/5.2/topics/composite-primary-key/","markdown":"/fr/5.2/topics/composite-primary-key.md","json":"/fr/5.2/topics/composite-primary-key.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/topics/composite-primary-key.txt","official":"https://docs.djangoproject.com/fr/5.2/topics/composite-primary-key/","inVersions":["6.1","6.0","5.2"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}