Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Bigint AutoField (fixes #56, #13774) #62

Closed
wants to merge 1 commit into from

2 participants

Pavel Zinovkin Anssi Kääriäinen
Pavel Zinovkin

Alternative approach to fix ticket 56.
Based on discussion #49
This approach doesn't change AutoField behavior. Only those who need extended int range may use it.
It keeps values ranges consistent between databases. Also it works nice with related fields.

Anssi Kääriäinen
Collaborator

To me it seems this needs some tests, mainly one for checking that the foreign key to a bigautofield is created properly as bigint. As per the policy of "commit or close when reviewing" I am closing this pull request.

Anssi Kääriäinen akaariai closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 13, 2012
  1. Pavel Zinovkin

    Bigint AutoField

    pzinovkin authored
This page is out of date. Refresh to see the latest.
3  django/db/backends/__init__.py
View
@@ -847,7 +847,8 @@ def convert_values(self, value, field):
internal_type = field.get_internal_type()
if internal_type == 'DecimalField':
return value
- elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
+ elif (internal_type and internal_type.endswith('IntegerField')
+ or internal_type.endswith('AutoField')):
return int(value)
elif internal_type in ('DateField', 'DateTimeField', 'TimeField'):
return value
1  django/db/backends/mysql/creation.py
View
@@ -6,6 +6,7 @@ class DatabaseCreation(BaseDatabaseCreation):
# be interpolated against the values of Field.__dict__ before being output.
# If a column type is set to None, it won't be included in the output.
data_types = {
+ 'BigAutoField': 'bigint AUTO_INCREMENT',
'AutoField': 'integer AUTO_INCREMENT',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
1  django/db/backends/oracle/creation.py
View
@@ -15,6 +15,7 @@ class DatabaseCreation(BaseDatabaseCreation):
# output (the "qn_" prefix is stripped before the lookup is performed.
data_types = {
+ 'BigAutoField': 'NUMBER(19)',
'AutoField': 'NUMBER(11)',
'BooleanField': 'NUMBER(1) CHECK (%(qn_column)s IN (0,1))',
'CharField': 'NVARCHAR2(%(max_length)s)',
1  django/db/backends/postgresql_psycopg2/creation.py
View
@@ -10,6 +10,7 @@ class DatabaseCreation(BaseDatabaseCreation):
# be interpolated against the values of Field.__dict__ before being output.
# If a column type is set to None, it won't be included in the output.
data_types = {
+ 'BigAutoField': 'bigserial',
'AutoField': 'serial',
'BooleanField': 'boolean',
'CharField': 'varchar(%(max_length)s)',
3  django/db/backends/sqlite3/base.py
View
@@ -191,7 +191,8 @@ def convert_values(self, value, field):
internal_type = field.get_internal_type()
if internal_type == 'DecimalField':
return util.typecast_decimal(field.format_number(value))
- elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
+ elif (internal_type and internal_type.endswith('IntegerField')
+ or internal_type.endswith('AutoField')):
return int(value)
elif internal_type == 'DateField':
return parse_date(value)
1  django/db/backends/sqlite3/creation.py
View
@@ -7,6 +7,7 @@ class DatabaseCreation(BaseDatabaseCreation):
# thing" given more verbose field definitions, so leave them as is so that
# schema inspection is more useful.
data_types = {
+ 'BigAutoField': 'integer',
'AutoField': 'integer',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
42 django/db/models/fields/__init__.py
View
@@ -205,6 +205,13 @@ def clean(self, value, model_instance):
self.run_validators(value)
return value
+ def _internal_to_db_type(self, internal_type, connection):
+ data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
+ try:
+ return connection.creation.data_types[internal_type] % data
+ except KeyError:
+ return None
+
def db_type(self, connection):
"""
Returns the database column data type for this field, for the provided
@@ -225,12 +232,14 @@ def db_type(self, connection):
# mapped to one of the built-in Django field types. In this case, you
# can implement db_type() instead of get_internal_type() to specify
# exactly which wacky database column type you want to use.
- data = DictWrapper(self.__dict__, connection.ops.quote_name, "qn_")
- try:
- return (connection.creation.data_types[self.get_internal_type()]
- % data)
- except KeyError:
- return None
+ return self._internal_to_db_type(self.get_internal_type(), connection)
+
+ def rel_db_type(self, connection):
+ """
+ Returns the database column data type for related field referencing
+ to this.
+ """
+ return self.db_type(connection)
@property
def unique(self):
@@ -514,14 +523,19 @@ class AutoField(Field):
'invalid': _(u"'%s' value must be an integer."),
}
- def __init__(self, *args, **kwargs):
+ def __init__(self, verbose_name=None, name=None, big=False, **kwargs):
assert kwargs.get('primary_key', False) is True, \
"%ss must have primary_key=True." % self.__class__.__name__
kwargs['blank'] = True
- Field.__init__(self, *args, **kwargs)
+ self.big = big
+ Field.__init__(self, verbose_name, name, **kwargs)
def get_internal_type(self):
- return "AutoField"
+ return 'AutoField' if not self.big else 'BigAutoField'
+
+ def rel_db_type(self, connection):
+ db_type = 'IntegerField' if not self.big else 'BigIntegerField'
+ return self._internal_to_db_type(db_type, connection)
def to_python(self, value):
if value is None:
@@ -1139,6 +1153,11 @@ class PositiveIntegerField(IntegerField):
def get_internal_type(self):
return "PositiveIntegerField"
+ def rel_db_type(self, connection):
+ if connection.features.related_fields_match_type:
+ return self.db_type(connection)
+ return self._internal_to_db_type('IntegerField', connection)
+
def formfield(self, **kwargs):
defaults = {'min_value': 0}
defaults.update(kwargs)
@@ -1150,6 +1169,11 @@ class PositiveSmallIntegerField(IntegerField):
def get_internal_type(self):
return "PositiveSmallIntegerField"
+ def rel_db_type(self, connection):
+ if connection.features.related_fields_match_type:
+ return self.db_type(connection)
+ return self._internal_to_db_type('IntegerField', connection)
+
def formfield(self, **kwargs):
defaults = {'min_value': 0}
defaults.update(kwargs)
13 django/db/models/fields/related.py
View
@@ -1018,19 +1018,8 @@ def formfield(self, **kwargs):
return super(ForeignKey, self).formfield(**defaults)
def db_type(self, connection):
- # The database column type of a ForeignKey is the column type
- # of the field to which it points. An exception is if the ForeignKey
- # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField,
- # in which case the column type is simply that of an IntegerField.
- # If the database needs similar types for key fields however, the only
- # thing we can do is making AutoField an IntegerField.
rel_field = self.rel.get_related_field()
- if (isinstance(rel_field, AutoField) or
- (not connection.features.related_fields_match_type and
- isinstance(rel_field, (PositiveIntegerField,
- PositiveSmallIntegerField)))):
- return IntegerField().db_type(connection=connection)
- return rel_field.db_type(connection=connection)
+ return rel_field.rel_db_type(connection=connection)
class OneToOneField(ForeignKey):
"""
11 docs/ref/models/fields.txt
View
@@ -320,13 +320,22 @@ Field types
``AutoField``
-------------
-.. class:: AutoField(**options)
+.. class:: AutoField([big=False, **options])
An :class:`IntegerField` that automatically increments
according to available IDs. You usually won't need to use this directly; a
primary key field will automatically be added to your model if you don't specify
otherwise. See :ref:`automatic-primary-key-fields`.
+.. attribute:: AutoField.big
+
+ .. versionadded:: 1.5
+
+ Optional. Either ``False`` or ``True``. Default is ``False``. Allow you
+ to use bigint for storing field values. This extends values range up to
+ max 64 bit integer (from 1 to 9223372036854775807).
+
+
``BigIntegerField``
-------------------
Something went wrong with that request. Please try again.