Opened 16 years ago
Closed 16 years ago
#7367 closed (invalid)
Cannot have non-primary-key OneToOneField to parent class
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | 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
I am using multi-table inheritance in the latest version from SVN (r7573), and I want a child class to have two OneToOneFields: one to the parent class as the primary-key parent link (the default created one with a primary key), and another to the parent class representing a different relation (which is not a primary key).
For example, a Restaurant is a Place, so it has a parent link to Place, but it also has one kitchen (which could be a place):
class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) class Restaurant(Place): serves_pizza = models.BooleanField() kitchen = models.OneToOneField(Place, related_name='restaurant_i_am_the_kitchen_of')
This shouldn't make kitchen_id a primary key, but it does (even if I set primary_key=False explicitly). It generates the following SQL:
BEGIN; CREATE TABLE `cms_place` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(50) NOT NULL, `address` varchar(80) NOT NULL ) ; CREATE TABLE `cms_restaurant` ( `serves_pizza` bool NOT NULL, `kitchen_id` integer NOT NULL UNIQUE PRIMARY KEY ) ; ALTER TABLE `cms_restaurant` ADD CONSTRAINT kitchen_id_refs_id_c2a98e0 FOREIGN KEY (`kitchen_id`) REFERENCES `cms_place` (`id`); COMMIT;
This behavior of making every OneToOneField that goes to a parent class a primary key happens in django/db/models/base.py on line 98-101:
if base in o2o_map: field = o2o_map[base] field.primary_key = True new_class._meta.setup_pk(field)
If I disable this and force it go to to the else clause (by making it 'if False'), then I get the desired SQL:
BEGIN; CREATE TABLE `cms_place` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(50) NOT NULL, `address` varchar(80) NOT NULL ) ; CREATE TABLE `cms_restaurant` ( `place_ptr_id` integer NOT NULL UNIQUE PRIMARY KEY, `serves_pizza` bool NOT NULL, `kitchen_id` integer NOT NULL UNIQUE ) ; ALTER TABLE `cms_restaurant` ADD CONSTRAINT place_ptr_id_refs_id_c2a98e0 FOREIGN KEY (`place_ptr_id`) REFERENCES `cms_place` (`id`); ALTER TABLE `cms_restaurant` ADD CONSTRAINT kitchen_id_refs_id_c2a98e0 FOREIGN KEY (`kitchen_id`) REFERENCES `cms_place` (`id`); COMMIT;
It seems that lines 98-101 shouldn't just check that the base class is in the o2o_map, but it should also check that the OneToOneField has parent_link set to True.
Change History (4)
comment:1 by , 16 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
comment:2 by , 16 years ago
That is, OneToOneField
really just represents a "is-a" relationship. For other kinds of relationships you should use the more generic ForeignKey
. In this case, ForeignKey(unique=True)
.
comment:3 by , 16 years ago
Resolution: | invalid |
---|---|
Status: | closed → reopened |
What about a mutable object that is sometimes A and sometimes B, maybe even sometimes both.
For example:
Tip (table describing tipping rules) applies to a Person (1-1).
Tip (same rules) applies to Restaurant (1-1).
I want to describe the tipping rules for a Person or a specific Restaurant (or a combination of the two). Each case is a (1-1). A foreign key would complicate things here and not reflect the true meaning of Tip. Tip is always 1-1 with at least one other table, that table can vary though.
This is a very common approach for adding properties to objects. Please provide an alternate or consider allowing non-primary key 1-1 tables.
comment:4 by , 16 years ago
Resolution: | → invalid |
---|---|
Status: | reopened → closed |
Invalid: By definition multiple one-to-one fields no longer makes it a one-to-one relationship.