Skip to content

Instantly share code, notes, and snippets.

@thomasyip
Created July 22, 2012 04:19
Show Gist options
  • Save thomasyip/3158388 to your computer and use it in GitHub Desktop.
Save thomasyip/3158388 to your computer and use it in GitHub Desktop.
Updated version of Django BigInt Patch for 64bit Primary Keys
"""
module mydjangolib.bigint_patch
A fix for the rather well-known ticket #399 in the django project.
Create and link to auto-incrementing primary keys of type bigint without
having to reload the model instance after saving it to get the ID set in
the instance.
Logs:
- v1.0: Created by Florian
- v1.1: Updated by Thomas
* Fixed missing param `connection`
* Used endswith for engine type check
(for better compatibility with `dj_database_url` and heroku)
* Added support for sqlite3 (which uses BIGINT by default)
* Added south's add_introspection_rules if south is defined
* Added BigOneToOneField and a short description
* Assumed file location: common/fields.py
"""
from django.core import exceptions
from django.conf import settings
from django.db.models import fields
from django.utils.translation import ugettext as _
from south.modelsinspector import add_introspection_rules
from django.db.models.fields.related import OneToOneField
__version__ = "1.1"
__author__ = "Florian Leitner"
__author__ = "Thomas Yip @ BeeDesk"
class BigIntegerField(fields.IntegerField):
def db_type(self, connection):
if settings.DATABASE_ENGINE.endswith('mysql'):
return "bigint"
elif settings.DATABASE_ENGINE.endswith('oracle'):
return "NUMBER(19)"
elif settings.DATABASE_ENGINE.endswith('postgres'):
return "bigint"
elif settings.DATABASE_ENGINE.endswith('sqlite3'):
return super(BigIntegerField, self).db_type(connection)
else:
raise NotImplemented
def get_internal_type(self):
return "BigIntegerField"
def to_python(self, value):
if value is None:
return value
try:
return long(value)
except (TypeError, ValueError):
raise exceptions.ValidationError(
_("This value must be a long integer."))
class BigAutoField(fields.AutoField):
def db_type(self, connection):
if settings.DATABASE_ENGINE.endswith('mysql'):
return "bigint AUTO_INCREMENT"
elif settings.DATABASE_ENGINE.endswith('oracle'):
return "NUMBER(19)"
elif settings.DATABASE_ENGINE.endswith('postgres'):
return "bigserial"
elif settings.DATABASE_ENGINE.endswith('sqlite3'):
return super(BigAutoField, self).db_type(connection)
else:
raise NotImplemented
def get_internal_type(self):
return "BigAutoField"
def to_python(self, value):
if value is None:
return value
try:
return long(value)
except (TypeError, ValueError):
raise exceptions.ValidationError(
_("This value must be a long integer."))
class BigForeignKey(fields.related.ForeignKey):
def db_type(self, connection):
rel_field = self.rel.get_related_field()
# next lines are the "bad tooth" in the original code:
if (isinstance(rel_field, BigAutoField) or
(not connection.features.related_fields_match_type and
isinstance(rel_field, BigIntegerField))):
# because it continues here in the django code:
# return IntegerField().db_type()
# thereby fixing any AutoField as IntegerField
return BigIntegerField().db_type(connection)
return rel_field.db_type(connection)
class BigOneToOneField(BigForeignKey, OneToOneField):
"""
If you use subclass model, you might need to name
the `ptr` field explicitly. This is the field type you
might want to use. Here is an example:
class Base(models.Model):
title = models.CharField(max_length=40, verbose_name='Title')
class Concrete(Base):
base_ptr = fields.BigOneToOneField(Base)
ext = models.CharField(max_length=12, null=True, verbose_name='Ext')
"""
pass
if 'south' in settings.INSTALLED_APPS:
add_introspection_rules([], ['^common\.fields\.BigIntegerField'])
add_introspection_rules([], ['^common\.fields\.BigAutoField'])
add_introspection_rules([], ['^common\.fields\.BigForeignKey'])
add_introspection_rules([], ['^common\.fields\.BigOneToOneField'])
@fxdgear
Copy link

fxdgear commented Oct 17, 2013

Any tricks for doing M2M fields?

@stodge
Copy link

stodge commented Oct 1, 2014

How does this work? I get an exception while applying the migration (Django 1.6):

django.db.utils.ProgrammingError: type "bigserial" does not exist

@roopesh90
Copy link

I was getting the same error as @stodge while implementing v1.1, but his forked and revised version of the script did the trick. It turns the datatype in the db in Postgres as bigserial. Hence I've forked his gist and updated it for Django 1.7. Thanks @stodge for the gist.
Here are the links:
stodge's revision for Django 1.6
my revision for Django 1.7

@rohitkhatri
Copy link

I'm new to django, and want to know where to keep this file so I can use these fields globally in any app?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment