Jay Taylor's notes

back to listing index

Django snippets: BigIntegerField and BigAutoField

[web search]
Original source (djangosnippets.org)
Tags: django python bigint djangosnippets.org
Clipped on: 2014-05-13

BigIntegerField and BigAutoField

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""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.
"""

from django.core import exceptions
from django.conf import settings
from django.db import connection
from django.db.models import fields
from django.utils.translation import ugettext as _

__version__ = "1.0"
__author__ = "Florian Leitner"

class BigIntegerField(fields.IntegerField):
    
    def db_type(self):
        if settings.DATABASE_ENGINE == 'mysql':
            return "bigint"
        elif settings.DATABASE_ENGINE == 'oracle':
            return "NUMBER(19)"
        elif settings.DATABASE_ENGINE[:8] == 'postgres':
            return "bigint"
        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):
        if settings.DATABASE_ENGINE == 'mysql':
            return "bigint AUTO_INCREMENT"
        elif settings.DATABASE_ENGINE == 'oracle':
            return "NUMBER(19)"
        elif settings.DATABASE_ENGINE[:8] == 'postgres':
            return "bigserial"
        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):
        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()
        return rel_field.db_type()

################################
# SAMPLE IMPLEMENTATION (REMOVE) #
################################
"""sample models.py implementation"""

from django.db import models
from mydjangolib import bigint_patch

class VeryLargeModel(models.Model)
    id = bigint_patch.BigAutoField(primary_key=True)
    data = models.TextField()

class ReferencingModel(models.Model)
    id = bigint_patch.BigAutoField(primary_key=True)
    target = bigint_patch.BigForeignKey(VeryLargeModel)
    more_data = models.TextField()
Search:
Advanced Search

Allows to create bigint (mysql), bigserial (psql), or NUMBER(19) (oracle) fields which have auto-increment set by using the AutoField of django, therefore ensuring that the ID gets updated in the instance when calling its 'save()' method.

If you would only subclass IntegerField to BigIntegerField and use that as your primary key, your model instance you create would not get the id attribute set when calling 'save()', buy instead you would have to query and load the instance from the DB again to get the ID.

Author:
fnl
Posted:
December 12, 2008
Language:
Python
Version:
1.0
Tags:
"primary key" bigserial bigint auto_increment
Score:
1 (after 1 ratings)

Tools

Comments

delcons (on June 9, 2009):

Hi, I am using your bigint_patch, it works very well. I tried to expand it to accomodate OneToOneFields and ManyToManyFields as well, but I am lacking some expertise for setting up the ManyToManyField. Have you tried this? I would appreciate any help or suggestions.

Thanks, Seth

#

munhitsu (on July 1, 2009):

For sqlite3 use (for both BigIntegerField, BigAutoField):

    if settings.DATABASE_ENGINE == 'sqlite3':
        return "integer"

#

peterbe (on June 9, 2010):

Does anybody have a new version of this for 1.2 or do I need to write one myself?

#

joksim (on January 15, 2011):

I would also be interested in support for 1.2.x. I have very limited knowledge of python and django.

If someone has a working version for this patch, I would be very grateful.

#

jayd (on August 31, 2011):

I have made a hack to get this to work with django 1.3

What you do is replace the:

if settings.DATABASE_ENGINE == 'mysql':

with:

if settings.DATABASES['default']['ENGINE'] == 'django.db.backends.mysql':

as in line 22, but with the relevant string for the other engines

And it works. HOWEVER... It only finds what the default database engine is set to, not the current model's engine. So that is a bit of a flaw.

If anyone knows how to access the model instance from this file, we could try something like:

from dhango.db import router ... if router.db_for_read(model_instance.class, instance=model_instance) = '?'

#

tomleaf (on July 21, 2012):

Thanks for the script. It was a very helpful starting point.

I ended up need a bit more to get it working end-to-end.

Here is my version: https://gist.github.com/3158388

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)

  • Returned super.db_type() for other database

  • Added south's add_introspection_rules if south is defined

  • Added BigOneToOneField and short description

  • Assumed file location: common/fields.py

#

Akshay.kapoor (on July 30, 2013):

Hey tomleaf, can you share the updated version of the patch which you have created for ManyToMany fields and OneToOne fields.. Thanks.

#

Username:
Password:
(Forgotten your password?)