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