#35956: Add composite foreign keys
-------------------------------------+-------------------------------------
     Reporter:  Csirmaz Bendegúz     |                    Owner:  David
                                     |  Sanders
         Type:  New feature          |                   Status:  assigned
    Component:  Database layer       |                  Version:  dev
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

 * cc: Simon Charette (added)

Comment:

 For anyone interested in enforcing composite foreign key constraints until
 this ticket gets fixed you might be interested in
 [https://github.com/charettes/django-fk-constraint this package] that adds
 the missing part of top of `ForeignObject` to enforce validation and
 constraint creation and enforcement.

 It can be used like the following

 {{{#!python
 class Tenant(models.Model):
     name = models.CharField()


 class TenantModel(models.Model):
     tenant = models.ForeignKey(
         Tenant,
         models.CASCADE,
     )
     uuid = models.UUIDField(default=uuid.uuid4)

     pk = models.CompositePrimaryKey("tenant", "uuid")

     class Meta:
         abstract = True


 class Product(TenantModel):
     name = models.CharField()


 class ProductPrice(TenantModel):
     product_uuid = models.UUIDField()
     product = models.ForeignObject(
         Product,
         models.CASCADE,
         from_fields=["tenant", "product_uuid"],
         to_fields=["tenant", "uuid"],
     )
     price = models.DecimalField(max_digits=10, decimal_places=2)

     class Meta:
         constraints = [
             ForeignKeyConstraint(
                 Product,
                 from_fields=["tenant", "product_uuid"],
                 to_fields=["tenant", "uuid"],
                 name="product_price_product_fk",
             )
         ]
 }}}

 TL;DR use `ForeignObject` and define a `ForeignKeyConstraint` with a
 similar signature.

 This works as `ForeignKey` in its current form is basically ''sugar'' to

 1. Define a concrete field
 2. Define a `ForeignObject`
 3. Define the equivalent of `ForeignKeyConstraint`

 In other words, these two definitions are equivalent

 {{{#!python
 class Book(models.Model):
     author_id = models.IntegerField()
     author = models.ForeignObject(
         Author, models.CASCADE, from_fields=["author_id"],
 to_fields=["id"]
     )

     class Meta:
         constraints = [
             ForeignKeyConstraint(
                 Author,
                 from_fields=["author_id"],
                 to_fields=["id"],
                 name="book_author_fk",
             )
         ]
 }}}

 and

 {{{#!python
 class Book(models.Model):
     author = models.ForeignKey(
         Author, models.CASCADE
     )
 }}}

 Now, whether something similar to `ForeignKeyConstraint` should exist as
 standalone documented form is debatable but getting `ForeignKey` ''sugar''
 to support multiple fields without it is going to be challenging as it
 will require figuring out what should be done with `attname` (AKA the
 implicit `_id` field).

 Until we have non-pk composite fields support I suspect we'll have to make
 the field fully ''virtual'' and require that concrete local `from_fields`
 are specified. That is making `.attname` be `None` and limit the ''sugar''
 to injecting a `constraints` entry as when a field is virtual (it's
 `db_column is None`) the schema editor completely ignores it.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35956#comment:13>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/01070197ae6d2db9-16d0fceb-be6b-476f-832f-afd3f8c30d72-000000%40eu-central-1.amazonses.com.

Reply via email to