Skip to content

Instantly share code, notes, and snippets.

@roopesh90
Forked from stodge/common [stash] fields.py
Last active August 29, 2015 14:16
Show Gist options
  • Save roopesh90/40a64b93a9ac1fb733b2 to your computer and use it in GitHub Desktop.
Save roopesh90/40a64b93a9ac1fb733b2 to your computer and use it in GitHub Desktop.
Updated version of Django BigInt Patch for 64bit Primary Keys for Django 1.7
"""
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
- v1.2: Updated by Mike
* Changed settings dictionary to support Django 1.6.
* Added support for 'postgis'
- v1.3: Updated by Roopesh
* Changed settings Dict to support Django 1.7
* Commented south code pieces as it wasn't required
"""
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.3"
__author__ = "Florian Leitner @ fnl"
__author__ = "Thomas Yip @ BeeDesk"
__author__ = "Mike Stoddart @ stodge"
__author__ = "Roopesh Nair @ roopesh90"
class BigIntegerField(fields.IntegerField):
def db_type(self, connection):
if 'mysql' in connection.__class__.__module__:
return "bigint"
elif 'oracle' in connection.__class__.__module__:
return "NUMBER(19)"
elif 'postgres' in connection.__class__.__module__:
return "bigint"
elif 'postgis' in connection.__class__.__module__:
return "bigint"
elif 'sqlite3' in connection.__class__.__module__:
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 'mysql' in connection.__class__.__module__:
return "bigint AUTO_INCREMENT"
elif 'oracle' in connection.__class__.__module__:
return "NUMBER(19)"
elif 'postgres' in connection.__class__.__module__:
return "bigserial"
elif 'postgis' in connection.__class__.__module__:
return "bigint"
elif 'sqlite3' in connection.__class__.__module__:
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'])
@roopesh90
Copy link
Author

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 and @thomasyip for the first revision.

Here are the links:
v1.0 by @fnl
v1.1 by @thomasyip
v1.2 by @stodge

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