#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 [email protected].
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