{"id":5155,"date":"2019-01-25T11:17:17","date_gmt":"2019-01-25T10:17:17","guid":{"rendered":"https:\/\/monodes.com\/predaelli\/?p=5155"},"modified":"2019-02-21T13:56:11","modified_gmt":"2019-02-21T12:56:11","slug":"multiple-fields-primary-keys-in-django","status":"publish","type":"post","link":"https:\/\/monodes.com\/predaelli\/2019\/01\/25\/multiple-fields-primary-keys-in-django\/","title":{"rendered":"Multiple fields primary keys in Django"},"content":{"rendered":"\n<p>I&#8217;m developing a little application in Django. <\/p>\n\n\n\n<p>Having developed a subtle dislike for UUIDs used as primary keys I tend to rely of the &#8220;natural keys&#8221; which are almost always identificable in a data model.<\/p>\n\n\n\n<p>Often thought those keys span over several fields. Think about a receipt of a multi-store multi-cashier store, their receipts are identificable by the tupla &lt;<code class=\"\" data-line=\"\">store_id, cashier_id, date, progressive_number<\/code>&gt;.<\/p>\n\n\n\n<p>It seems that <a href=\"https:\/\/stackoverflow.com\/questions\/16800375\/how-can-set-two-field-primary-key-for-my-models-in-django\">Django currently does not allow<\/a>, at least out-of-the-box to use several fields grouped into a tuple as primary key. It&#8217;s also explained in <a href=\"https:\/\/docs.djangoproject.com\/en\/2.1\/faq\/models\/\">its FAQs<\/a>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p> <br \/>Do Django models support multiple-column primary keys?<a href=\"https:\/\/docs.djangoproject.com\/en\/2.1\/faq\/models\/#do-django-models-support-multiple-column-primary-keys\">\u00b6<\/a><br \/> No. Only single-column primary keys are supported.<br \/> But this isn\u2019t an issue in practice, because there\u2019s nothing stopping you from adding other constraints (using the <code class=\"\" data-line=\"\">unique_together<\/code> model option or creating the constraint directly in your database), and enforcing the uniqueness at that level. Single-column primary keys are needed for things such as the admin interface to work; e.g., you need a simple way of being able to specify an object to edit or delete. <\/p><\/blockquote>\n\n\n\n<p>So I understand why lazy developers use UUIDs.<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/simone\">Simone Federici<\/a> has written <strong><a href=\"https:\/\/github.com\/simone\/django-compositekey\">django-compositekey<\/a><\/strong>  but AFAICS it support only Django 1.x and not the current 2.x <br \/>It seems I have to maintain uniqueness django-way and I don&#8217;t like it the way it is: it looks like an ugly kludge.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Update:<\/h2>\n\n\n\n<p>I&#8217;ve been busy with completely unrelated issues but I still haven&#8217;t solved this.  Apparently neither Django developers as they wrote in &#8220;<a href=\"https:\/\/code.djangoproject.com\/wiki\/MultipleColumnPrimaryKeys\">Multi-Column Primary Key support<\/a>&#8220;. Too bad, I&#8217;ll make up those keys composing primary key strings like <code class=\"\" data-line=\"\">&quot;$store_id-$cashier_id-YYYY-MM-DD-$progressive_number&quot;<\/code>. Hoping that my little hack will not still be in use in year ten thousand<\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p> <br \/><br \/> I would use a default primary key (auto field), and use the  meta class property, <code class=\"\" data-line=\"\">unique_together<\/code><br \/> <code class=\"\" data-line=\"\">class Hop(models.Model):     migration = models.ForeignKey(&#039;Migration&#039;)     host = models.ForeignKey(User, related_name=&#039;host_set&#039;)     class Meta:         unique_together = ((&quot;migration&quot;, &quot;host&quot;),)<\/code><br \/> It would act as a &#8220;surrogate&#8221; primary key column. <br \/> If you really want to create a multi-column primary key, look into <a href=\"https:\/\/github.com\/simone\/django-compositekey\">this app<\/a> <\/p><\/blockquote>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p class=\"excerpt\">I&#8217;m developing a little application in Django. Having developed a subtle dislike for UUIDs used as primary keys I tend to rely of the &#8220;natural keys&#8221; which are almost always identificable in a data model. Often thought those keys span over several fields. Think about a receipt of a multi-store multi-cashier store, their receipts are&hellip;<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"https:\/\/monodes.com\/predaelli\/2019\/01\/25\/multiple-fields-primary-keys-in-django\/\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[229,113],"tags":[],"class_list":["post-5155","post","type-post","status-publish","format-standard","hentry","category-django","category-python"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6daft-1l9","jetpack-related-posts":[{"id":10654,"url":"https:\/\/monodes.com\/predaelli\/2023\/07\/23\/10654\/","url_meta":{"origin":5155,"position":0},"title":"Django-LiveView","author":"Paolo Redaelli","date":"2023-07-23","format":"link","excerpt":"Django LiveView: Framework for creating Realtime SPAs using HTML over the Wire technology django-liveview-demo.andros.dev\/","rel":"","context":"In &quot;Python&quot;","block_context":{"text":"Python","link":"https:\/\/monodes.com\/predaelli\/category\/python\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":5109,"url":"https:\/\/monodes.com\/predaelli\/2019\/01\/07\/stable-yet-experimental\/","url_meta":{"origin":5155,"position":1},"title":"Stable yet experimental","author":"Paolo Redaelli","date":"2019-01-07","format":false,"excerpt":"This tutorial is written for Django 2.1, which supports Python 3.5 and later From: Writing your first Django app, part 1 | Django documentation | Django I couldn't find Djiango 2 in my CentOS box. Of course, it's meant to use only rock-stable versions, I told myself. I tought to\u2026","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":10758,"url":"https:\/\/monodes.com\/predaelli\/2023\/09\/01\/using-csv-file-as-data-storage-and-access\/","url_meta":{"origin":5155,"position":2},"title":"Using CSV File as data storage and access","author":"Paolo Redaelli","date":"2023-09-01","format":false,"excerpt":"Thanks adamchainz! You can use \u201cCSV\u201d table storage in (at least) these database backends: SQLite: https:\/\/www.sqlite.org\/csv.html 42 MySQL\/MariaDB via the \u201cCSV\u201d storage engine: https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/csv-storage-engine.html 15 . Or MariaDB via the CONNECT storage engine: https:\/\/mariadb.com\/kb\/en\/connect\/ 1 However these will be slow though. Changes to CSV based tables require a lot of\u2026","rel":"","context":"In &quot;Django&quot;","block_context":{"text":"Django","link":"https:\/\/monodes.com\/predaelli\/category\/python\/django\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4347,"url":"https:\/\/monodes.com\/predaelli\/2018\/05\/26\/transcrypt-python-in-the-browser-lean-fast-open\/","url_meta":{"origin":5155,"position":3},"title":"Transcrypt &#8211; Python in the browser &#8211; Lean, fast, open!","author":"Paolo Redaelli","date":"2018-05-26","format":false,"excerpt":"Well, life is full of surprises.... The Transcrypt Python to JavaScript compiler makes it possible to program lean and fast browser applications in Python. Transcrypt applications can use any JavaScript library and can also run on top of Node.js or be used in combination with Django. Sorgente: Transcrypt - Python\u2026","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":5100,"url":"https:\/\/monodes.com\/predaelli\/2019\/01\/02\/choosing-a-framework\/","url_meta":{"origin":5155,"position":4},"title":"Choosing a framework","author":"Paolo Redaelli","date":"2019-01-02","format":false,"excerpt":"I've been asked to develop an application to record incoming shipments of loose materials, more precisely excavated material to be processed - washed, crushed and sieved - to produce construction materials such as sand, gravels and coarse aggregates. Ten years ago I would have used Qt or Gtk for the\u2026","rel":"","context":"In &quot;PHP&quot;","block_context":{"text":"PHP","link":"https:\/\/monodes.com\/predaelli\/category\/php\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":5102,"url":"https:\/\/monodes.com\/predaelli\/2019\/01\/03\/auto-generated-primary-keys-friends-or-foes-3\/","url_meta":{"origin":5155,"position":5},"title":"Auto-generated Primary Keys, friends or foes?","author":"Paolo Redaelli","date":"2019-01-03","format":false,"excerpt":"Time to read againg Auto-generated Primary Keys, friends or foes? of the almighty Davide. I will save it somewhere, hoping that it will never go offline. In that case you will find it here. \u00a0","rel":"","context":"In &quot;Documentations&quot;","block_context":{"text":"Documentations","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/5155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/comments?post=5155"}],"version-history":[{"count":0,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/5155\/revisions"}],"wp:attachment":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/media?parent=5155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/categories?post=5155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/tags?post=5155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}