views:

59

answers:

3

Consider the case where a CHAR field primary_key is required in order to define a ForeignKey relationship.

After some initial investigation I have identified the following possibilities, each with their own drawbacks:

1) Using 'primary_key=True'.

Example 1:

class Collection(models.Model):
    code = models.CharField(primary_key=True, max_length=3)

class Item(models.Model):
    code = models.CharField(primary_key=True, max_length=255, unique=True)
    collection = models.ForeignKey('Collection', related_name='items')

Potential Drawback: Might result in issues when incorporating 3rd party apps as certain 3rd party django apps depend on the default 'id' PK integer field.

2) Use the 'to_field' / 'through' option instead.

Example 2:

class Collection(models.Model):
    code = models.CharField(Max_length=3, unique=True)

class Item(models.Model):
    collection = models.ForeignKey('Collection', to_field='code', related_name='items')

This will allow 'Collection' to have its own id primary_key, so it solves the problem of playing nicely with 3rd party django apps.

Potential drawbacks: After further investigation I discovered the following open Django ORM tickets and bugs with regards to dealing with mix of CHAR / INT primary_keys in FK and many-to-many relationships.

http://code.djangoproject.com/ticket/11319 and 13343

Conclusion:

Option 1 is better than Option 2.
However:
Are there many 3rd party apps that depend on the integer primary_key?
Is there an easy workaround for this limitation?
Are there any other drawbacks using a CHAR primary_key?

+1  A: 

GenericForeignKeys would suffer since they all need to use the same type for a foreign PK. As long as you stay away from them, you should be fine.

Ignacio Vazquez-Abrams
Hi Ignacio, do you have any reference to the fact that GenericForeignKeys require same type for foreign PK's?
AtlasStrategic
No, but it can be derived from the fact that the second argument to the `GenericForeignKey` constructor is the name of a field, and that a field can only have a single type.
Ignacio Vazquez-Abrams
+1  A: 

I had troubles in the django admin application when using char field as primary key. See http://stackoverflow.com/questions/2011629/unicode-error-when-saving-an-object-in-django-admin for details

Restoring the id as primary key was difficult see http://stackoverflow.com/questions/2055784/what-is-the-best-approach-to-change-primary-keys-in-an-existing-django-app.

From this experience, I think that using something else than the id as primary key is a bad idea.

luc
A: 

I personally go for Option 2 in my apps, as that's how I've seen most third-party applications do it, and it avoids the slew of problems that you already brought up in your post with regards to mixing CHAR and INT Primary Keys in the Django ORM.

I haven't run into a single issue yet just using unique=True, so I don't really see any drawbacks to doing that instead.

Pewpewarrows
Hi Pewpewwarrows, I suppose you mean "Option 1 in my apps"? Example 2 (Option 2) has the issues / bugs with mixing CHAR and INT PK's.
AtlasStrategic