Django

Code

Ticket #7367 (closed: invalid)

Opened 4 months ago

Last modified 3 months ago

Cannot have non-primary-key OneToOneField to parent class

Reported by: mturtle@gmail.com Assigned to: nobody
Milestone: Component: Database layer (models, ORM)
Version: SVN Keywords:
Cc: Triage Stage: Unreviewed
Has patch: 0 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

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.

Attachments

Change History

06/08/08 13:28:37 changed by jbronn

  • status changed from new to closed.
  • needs_better_patch changed.
  • resolution set to invalid.
  • needs_tests changed.
  • needs_docs changed.

Invalid: By definition multiple one-to-one fields no longer makes it a one-to-one relationship.

06/08/08 13:40:28 changed by jacob

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

06/23/08 14:48:17 changed by pkenjora@gmail.com

  • status changed from closed to reopened.
  • resolution deleted.

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.

07/08/08 18:56:29 changed by emulbreh

  • status changed from reopened to closed.
  • resolution set to invalid.

Add/Change #7367 (Cannot have non-primary-key OneToOneField to parent class)




Change Properties
Action