Opened 7 years ago

Closed 4 years ago

Last modified 4 years ago

#28824 closed New feature (wontfix)

Allow different Foreign Keys to share same underlying DB column

Reported by: klass-ivan Owned by: nobody
Component: Database layer (models, ORM) Version: 1.11
Severity: Normal Keywords: foreigh key, db_column,
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

class A(Model):
    uid = CharField(unique=True)
    # other fields

class B(Model):
    uid = CharField(unique=True)
    # other fields

class C(Model):
   # other fields
   uid  = CharField(unique=False)
   a = ForeignKey(to=A, to_field='uid', db_column='uid', null=True)
   b = ForeignKey(to=B, to_field='uid', db_column='uid', null=True)

Gives an error:

Field 'b' has column name 'uid' that is used by another field.
	HINT: Specify a 'db_column' for the field.

However, ForeignKey field is a ORM relation based on underlying column anyway.
I think it won't break anything if we allow different foreign keys to share same underlying column.
This adds more flexibility and will allow better django "on-boarding" process for legacy projects.
It will be also useful when A or B is proxy model - so we can get different proxy objects by different foreign keys referencing same DB row.

Another example can be found here:
https://stackoverflow.com/questions/36911804/django-use-same-column-for-two-foreign-keys

Change History (7)

comment:1 by klass-ivan, 7 years ago

If skip _check_column_name_clashes in models.base, the next issue will be in _do_insert - DB error that "Column '<column_name>' specified twice"

comment:2 by Josh Smeaton, 7 years ago

I'm struggling to see where the value for this change would be, and how common a situation this really is. I think the benefit of supporting this would be outweighed by users that are incorrectly duplicating keys on their models with copy/paste and running into legitimate issues.

Further, I believe you can (probably) get similar behaviour working if you reverse the location of your keys, and switch to using OneToOne. I haven't tested this myself, but I think this would work:

class A(Model):
    uid = CharField(unique=True)
    c = OneToOneField(to=C, to_field='uid', db_column='uid', null=True)

class B(Model):
    uid = CharField(unique=True)
    c = OneToOneField(to=C, to_field='uid', db_column='uid', null=True)

class C(Model):
   # other fields
   uid  = CharField(unique=False)

c = get_c(..)
c.a # fine
c.b # fine

comment:3 by Tim Graham, 7 years ago

Resolution: wontfix
Status: newclosed

in reply to:  2 comment:4 by Matt Ferrante, 4 years ago

Would a valid case for this be to traverse from A to B without joining through C.

A.objects.filter(c__b__name="foo")
# below should be more performant than above
A.objects.filter(b__name="foo")

I have encountered this same issue. I end up defining the same field on the A model and populating it with the same Value to avoid making unnecessary joins through certain tables. This seems excessive though. It would be nice if I could specify more relationships. If something like the FilteredRelationship was used to define ad-hoc relationships, that could be helpful. It would need better Nested Relationship support though (https://code.djangoproject.com/ticket/29789)

comment:5 by Matt Ferrante, 4 years ago

Resolution: wontfix
Status: closednew

Reopening because I think there is a valid case for this, referenced in my previous comment.

comment:6 by Mariusz Felisiak, 4 years ago

Resolution: wontfix
Status: newclosed

Matt, please follow triaging guidelines with regards to wontfix tickets.

Moreover this comment is still valid, even with a use case:

I'm struggling to see where the value for this change would be, and how common a situation this really is. I think the benefit of supporting this would be outweighed by users that are incorrectly duplicating keys on their models with copy/paste and running into legitimate issues.

comment:7 by James Lin, 4 years ago

This issue becomes more apparent when creating models on top of existing database just to read from.

Note: See TracTickets for help on using tickets.
Back to Top