diff --git a/django/core/management/sql.py b/django/core/management/sql.py index 8f7f6a023a1c3..ed76bc4e35914 100644 --- a/django/core/management/sql.py +++ b/django/core/management/sql.py @@ -302,7 +302,8 @@ def sql_model_create(model, style, known_models=set()): if opts.has_auto_field: # Add any extra SQL needed to support auto-incrementing primary keys. - autoinc_sql = connection.ops.autoinc_sql(opts.db_table) + auto_column = opts.auto_field.db_column or opts.auto_field.name + autoinc_sql = connection.ops.autoinc_sql(opts.db_table, auto_column) if autoinc_sql: for stmt in autoinc_sql: final_output.append(stmt) @@ -385,7 +386,7 @@ def many_to_many_sql_for_model(model, style): final_output.append('\n'.join(table_output)) # Add any extra SQL needed to support auto-incrementing PKs - autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table()) + autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table(), 'id') if autoinc_sql: for stmt in autoinc_sql: final_output.append(stmt) diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index f3c6f5925864e..1b6ba07f241ed 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -56,7 +56,7 @@ class BaseDatabaseOperations(object): a backend performs ordering or calculates the ID of a recently-inserted row. """ - def autoinc_sql(self, table): + def autoinc_sql(self, table, column): """ Returns any SQL needed to support auto-incrementing primary keys, or None if no SQL is necessary. diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 23ce30f37eb44..4093b69be69ce 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -31,20 +31,23 @@ class DatabaseFeatures(BaseDatabaseFeatures): uses_custom_queryset = True class DatabaseOperations(BaseDatabaseOperations): - def autoinc_sql(self, table): + def autoinc_sql(self, table, column): # To simulate auto-incrementing primary keys in Oracle, we have to # create a sequence and a trigger. sq_name = get_sequence_name(table) tr_name = get_trigger_name(table) + tbl_name = self.quote_name(table) + col_name = self.quote_name(column) sequence_sql = 'CREATE SEQUENCE %s;' % sq_name trigger_sql = """ - CREATE OR REPLACE TRIGGER %s - BEFORE INSERT ON %s + CREATE OR REPLACE TRIGGER %(tr_name)s + BEFORE INSERT ON %(tbl_name)s FOR EACH ROW - WHEN (new.id IS NULL) + WHEN (new.%(col_name)s IS NULL) BEGIN - SELECT %s.nextval INTO :new.id FROM dual; - END;/""" % (tr_name, self.quote_name(table), sq_name) + SELECT %(sq_name)s.nextval + INTO :new.%(col_name)s FROM dual; + END;/""" % locals() return sequence_sql, trigger_sql def date_extract_sql(self, lookup_type, field_name): diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 3792a30a88d79..34d998c219624 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -433,6 +433,7 @@ def contribute_to_class(self, cls, name): assert not cls._meta.has_auto_field, "A model can't have more than one AutoField." super(AutoField, self).contribute_to_class(cls, name) cls._meta.has_auto_field = True + cls._meta.auto_field = self def formfield(self, **kwargs): return None diff --git a/django/db/models/options.py b/django/db/models/options.py index ad813ae0f7ce3..502cbc4a65b05 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -33,7 +33,7 @@ def __init__(self, meta): self.admin = None self.meta = meta self.pk = None - self.has_auto_field = False + self.has_auto_field, self.auto_field = False, None self.one_to_one_field = None self.parents = [] diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py index 7aa9e2a7c4251..00c3bc96f089c 100644 --- a/tests/regressiontests/model_regress/models.py +++ b/tests/regressiontests/model_regress/models.py @@ -20,6 +20,11 @@ class Meta: def __unicode__(self): return self.headline +class Movie(models.Model): + #5218: Test models with non-default primary keys / AutoFields + movie_id = models.AutoField(primary_key=True) + name = models.CharField(max_length=60) + __test__ = {'API_TESTS': """ (NOTE: Part of the regression test here is merely parsing the model declaration. The verbose_name, in particular, did not always work.)