Opened 5 years ago

Closed 5 years ago

#13481 closed (worksforme)

Allow db_column on ForeignKey

Reported by: malthe Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Keywords:
Cc: farcepest@… Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

The db_column does not currently apply to ForeignKey, although this could easily be made to work:

    def get_attname(self):
        return self.db_column or '%s_id' % self.name

This would enable you to name the underlying field of a relation.

Change History (7)

comment:1 Changed 5 years ago by kmtracey

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to closed

I have a project with db_column specified on just about every model field (database existed before Django), including foreign keys. So I'm not understanding how you can say db_column does not apply for ForeignKey. In my experience it's working just fine.

comment:2 Changed 5 years ago by malthe

  • Resolution worksforme deleted
  • Status changed from closed to reopened

I wanted to change the ORM table name along with the database column name. Perhaps it's better to support a column parameter, since the focus is really on the table name.

comment:3 Changed 5 years ago by Alex

  • Resolution set to worksforme
  • Status changed from reopened to closed

This bug was, correctly, marked as working fine. If you have another bug please file a new bug.

comment:4 Changed 5 years ago by kmtracey

But please do not open a new ticket for function that already exists. Controlling the name of the database table is done via the db_table Meta option: http://docs.djangoproject.com/en/dev/ref/models/options/#db-table. Just as the columns in my previously-mentioned project do not conform to Django's naming convention, neither do the table names, and to accommodate that this project has db_table specified for every model. If there is something you are having difficulty with perhaps if you posted details to someplace like django-users someone might be able to help. Both things you have asked for here seem to already be possible with existing function.

comment:5 Changed 5 years ago by farcepest

  • Cc farcepest@… added
  • Resolution worksforme deleted
  • Status changed from closed to reopened

I can reproduce this problem using trunk [13263].

In my environment, I am using a legacy database on DB2.

socrates.OASIS.models:

from django.db import models

# Create your models here.

class Building(models.Model):

    class Meta:

        managed = False
        db_table = 'pffi"."bffi92a'

    id = models.CharField(
        db_column = 'bbnum',
        primary_key = True,
    )

    bbname1 = models.CharField(
        db_column = 'bbname1',
        max_length = 18,
    )

    # ... bunch of fields

class Room(models.Model):
    
    class Meta:

        managed = False
        db_table = 'pffi"."bffi93a'
        unique_together = ('bbnum', 'brnum')

    bbnum = models.ForeignKey(
        Building,
    )

    brnum = models.CharField(
        db_column = 'brnum',
        max_length = 5,
        primary_key = True, # a lie
    )

    # This database has a composite primary key but I only need
    # it read-only.
  
In [1]: from socrates.OASIS.models import Building,Room

In [2]: %pdb
Automatic pdb calling has been turned ON

In [3]: r147=Room.objects.using("oasis").get(bbnum="0055",brnum="0147A")

---------------------------------------------------------------------------
DatabaseError                             Traceback (most recent call last)
... traceback trimmed ...
ipdb> up
> /home/adustman/Development/socrates-env/lib/python2.6/site-packages/ibm_db_dbi.py(1152)execute()
   1151         self._all_stmt_handlers = []
-> 1152         self._prepare_helper(operation)
   1153         self._set_cursor_helper()

ipdb> up
> /home/adustman/Development/socrates-env/lib/python2.6/site-packages/django/db/backends/ibm_db_django/base.py(215)execute()
    214         except (TypeError):
--> 215             return None
    216 

ipdb> up
> /home/adustman/Development/socrates-env/lib/python2.6/site-packages/django/db/backends/util.py(21)execute()
     20                 'sql': sql,
---> 21                 'time': "%.3f" % (stop - start),
     22             })

ipdb> print sql
SELECT "PFFI"."BFFI93A"."BBNUM_ID", "PFFI"."BFFI93A"."BRNUM",
...
FROM "PFFI"."BFFI93A" WHERE ( "PFFI"."BFFI93A"."BBNUM_ID" = 0055  AND  "PFFI"."BFFI93A"."BRNUM" = 0147A )
ipdb> 

Note that Django incorrectly generates a BBNUM_ID column when referring to the Building class through the ForeignKey relation, i.e. it should use the values of db_column on Building.bbnum ('bbnum').

In contrast, using Building directly works fine, and does not raise an exception.

comment:6 Changed 5 years ago by farcepest

Additional note: If I add db_column = "bbnum" to the definition of Room.bbnum (the ForeignKey), then I don't even get as far as generating bad SQL.

In [14]: r147=Room.objects.using("oasis").get(bbnum='0055',brnum="0147A")
ValueError: Cannot assign "u'0055'": "Room.bbnum" must be a "Building" instance.
In [15]: brooks=Building.objects.using('oasis').get(id='0055')
In [16]: r147=Room.objects.using("oasis").get(bbnum=brooks,brnum="0147A")
ValueError: Cannot assign "u'0055'": "Room.bbnum" must be a "Building" instance.
In [17]: r147=Room.objects.using("oasis").get(bbnum__id='0055',brnum="0147A")
ValueError: Cannot assign "u'0055'": "Room.bbnum" must be a "Building" instance.

Even when I pass it a Building instance, it complains about needing a Building instance.

comment:7 Changed 5 years ago by russellm

  • Resolution set to worksforme
  • Status changed from reopened to closed

Our testing indicates that db_column works fine in Django core. If you're having problems with DB2, the I suggest you take that up with the providers of the DB2 backend. The DB2 backend isn't part of the official Django distribution, and as such, bugs in that backend shouldn't be logged in this Trac.

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