I wanted to be able to use Django's admin interface to edit PostgreSQL inherited tables. The normal use would be to have a single sequence on the parent table and let the children inherit that, so that the IDs across all children are unique. However, Django assumes that the sequence name is tablename_columnname_seq which does not apply in this case.
I have created the folloiwing patch to allow one to override the default sequence name with one of your choosing by adding a seq_name= parameter when defining the field, like this:
class PeerIAX(models.Model):
class Admin: pass
id = models.AutoField(primary_key=True, seq_name='asterisk_peer_id_seq')
description = models.CharField(maxlength=255)
hostname = models.CharField(maxlength=255)
username = models.CharField(maxlength=255)
secret = models.CharField(maxlength=255)
def __str__(self):
return description
In case it's not obvious, this simple patch does not add support to Django to actually *create* the tables. I hand-created them like so:
CREATE TABLE asterisk_peer (
id SERIAL NOT NULL PRIMARY KEY,
description VARCHAR(255) NOT NULL
);
CREATE TABLE asterisk_peer_iax (
hostname VARCHAR(255) NOT NULL,
username VARCHAR(255) NOT NULL,
secret VARCHAR(255) NOT NULL
) INHERITS (asterisk_peer);
The patch is below. I abandon copyright on the code and you are welcome to incorporate the patch into Django as you see fit.
diff -rduP ../Django-0.91-py2.3.egg.orig/django/db/backends/ado_mssql/base.py ./django/db/backends/ado_mssql/base.py
--- ../Django-0.91-py2.3.egg.orig/django/db/backends/ado_mssql/base.py 2006-05-15 13:52:49.000000000 +0100
+++ ./django/db/backends/ado_mssql/base.py 2006-05-20 20:09:24.000000000 +0100
@@ -94,7 +94,9 @@
dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall
-def get_last_insert_id(cursor, table_name, pk_name):
+def get_last_insert_id(cursor, table_name, pk_name, seq_name):
+ # FIXME: seq_name might be a useful thing to add to backends other than
+ # PostgreSQL
cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
return cursor.fetchone()[0]
diff -rduP ../Django-0.91-py2.3.egg.orig/django/db/backends/mysql/base.py ./django/db/backends/mysql/base.py
--- ../Django-0.91-py2.3.egg.orig/django/db/backends/mysql/base.py 2006-05-15 13:52:49.000000000 +0100
+++ ./django/db/backends/mysql/base.py 2006-05-20 20:10:01.000000000 +0100
@@ -117,7 +117,9 @@
dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall
-def get_last_insert_id(cursor, table_name, pk_name):
+def get_last_insert_id(cursor, table_name, pk_name, seq_name):
+ # FIXME: seq_name might be a useful thing to add to backends other than
+ # PostgreSQL
return cursor.lastrowid
def get_date_extract_sql(lookup_type, table_name):
diff -rduP ../Django-0.91-py2.3.egg.orig/django/db/backends/postgresql/base.py ./django/db/backends/postgresql/base.py
--- ../Django-0.91-py2.3.egg.orig/django/db/backends/postgresql/base.py 2006-05-15 13:52:49.000000000 +0100
+++ ./django/db/backends/postgresql/base.py 2006-05-20 19:40:12.000000000 +0100
@@ -75,8 +75,10 @@
"Returns all rows from a cursor as a dict"
return cursor.dictfetchall()
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
+def get_last_insert_id(cursor, table_name, pk_name, seq_name):
+ if seq_name is None:
+ seq_name = "%s_%s_seq" % (table_name, pk_name)
+ cursor.execute("SELECT CURRVAL('\"%s\"')" % seq_name)
return cursor.fetchone()[0]
def get_date_extract_sql(lookup_type, table_name):
diff -rduP ../Django-0.91-py2.3.egg.orig/django/db/backends/sqlite3/base.py ./django/db/backends/sqlite3/base.py
--- ../Django-0.91-py2.3.egg.orig/django/db/backends/sqlite3/base.py 2006-05-15 13:52:49.000000000 +0100
+++ ./django/db/backends/sqlite3/base.py 2006-05-20 20:10:11.000000000 +0100
@@ -90,7 +90,9 @@
dictfetchmany = util.dictfetchmany
dictfetchall = util.dictfetchall
-def get_last_insert_id(cursor, table_name, pk_name):
+def get_last_insert_id(cursor, table_name, pk_name, seq_name):
+ # FIXME: seq_name might be a useful thing to add to backends other than
+ # PostgreSQL
return cursor.lastrowid
def get_date_extract_sql(lookup_type, table_name):
diff -rduP ../Django-0.91-py2.3.egg.orig/django/db/models/base.py ./django/db/models/base.py
--- ../Django-0.91-py2.3.egg.orig/django/db/models/base.py 2006-05-15 13:52:49.000000000 +0100
+++ ./django/db/models/base.py 2006-05-20 19:55:52.000000000 +0100
@@ -187,7 +187,7 @@
(backend.quote_name(self._meta.db_table), ','.join(field_names),
','.join(placeholders)), db_values)
if self._meta.has_auto_field and not pk_set:
- setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
+ setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column, self._meta.pk.seq_name))
transaction.commit_unless_managed()
# Run any post-save hooks.
diff -rduP ../Django-0.91-py2.3.egg.orig/django/db/models/fields/__init__.py ./django/db/models/fields/__init__.py
--- ../Django-0.91-py2.3.egg.orig/django/db/models/fields/__init__.py 2006-05-15 13:52:49.000000000 +0100
+++ ./django/db/models/fields/__init__.py 2006-05-20 19:53:28.000000000 +0100
@@ -68,7 +68,7 @@
core=False, rel=None, default=NOT_PROVIDED, editable=True,
prepopulate_from=None, unique_for_date=None, unique_for_month=None,
unique_for_year=None, validator_list=None, choices=None, radio_admin=None,
- help_text='', db_column=None):
+ help_text='', db_column=None,seq_name=None):
self.name = name
self.verbose_name = verbose_name
self.primary_key = primary_key
@@ -84,6 +84,7 @@
self.radio_admin = radio_admin
self.help_text = help_text
self.db_column = db_column
+ self.seq_name = seq_name
# Set db_index to True if the field has a relationship and doesn't explicitly set db_index.
self.db_index = db_index