#167 closed defect (duplicate)
ForeignKey should also take string arg instead of class name
Reported by: | Manuzhai | Owned by: | Adrian Holovaty |
---|---|---|---|
Component: | Metasystem | Version: | |
Severity: | normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Some ForeignKey relationships might be circular, due to the somewhat linear fashion of source code, this doesn't work so well. For example, you could have a Person and an Address, with a Person living at an Address as well as the Address having an owner who is, incidentally, a Person. It would be nice if
ForeignKey('Person')
would be supported as well as
ForeignKey(Person)
but according to jacobkm, that might not work. In which it would be
ForeignKey('app.people')
to make it easier on the black magic scripts to find the right model.
Change History (3)
comment:1 by , 19 years ago
comment:2 by , 19 years ago
The correct way to handle this with PostgreSQL is to make deferr checking of constraints, and then do the circular insert or delete inside a transaction with deferred foreign key checking. See SET CONSTRAINTS for setting these per transaction. By making the foreign key INITIALLY DEFERRED, all transactions can do circular operations.
comment:3 by , 19 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
This has been superceded by #1662.
Circular foreign-key references are tricky to get right. INSERTs, DELETEs, even table creation: you've got to do everything in the right order. It is possible, but it should probably wait until after a 1.0 release.
The only way to even get circular foreign-key relations into the database in the first place is to split out the table creation from the adding of foreign-key constraints. The way the code currently works, we do the equivalent of:
But that will only work if the "person" table already exists at that point. If "person" also needs to point to "address", and address back to person, something like the following is needed:
This works in PostgreSQL and MySQL; SQLite doesn't have the ALTER TABLE ADD FOREIGN KEY syntax at all. But then, SQLite doesn't actually enforce foreign keys (see http://www.sqlite.org/omitted.html), so that omission doesn't actually hurt.
Both PostgreSQL and MySQL let you insert NULLs in a FOREIGN KEY field (as long as you haven't declared it NOT NULL, of course). This can be the only way to insert data that contains circular references:
Deletes from two self-referencing tables also take an intermediate step:
How does this relate to Django? Besides the obvious observation that circular foreign-key references are tricky, and that this feature should probably be left until after a 1.0 release, here's what I see as being necessary if this feature is to work at all:
There's probably a lot more than I'm omitting, but that's a start.