We recently started the test and upgrade process to bring our large
Django applications more up to date with 1.3 to help test new things.
We found that http://code.djangoproject.com/changeset/13363 introduced
backwards incompatible changes.

Previously, using PostgreSQL, it was possible to take a manually
defined INTEGER column and create a sequence and set the nextval()
just as the SERIAL type does. Prior to 1.3, this worked fine as long
as you named your sequence correctly.

For example, we had a table named nut_food with "id INTEGER NOT NULL
DEFAULT NEXTVAL('nut_food_id_seq'::regclass)" -- so at first glance,
all appeared correct. However, inserting a new record with
"Food.objects.create(..) would *silently* fail and assign None to the
instance in Python, despite the record actually having an ID in the
database.

Two things of note:

a) To fix this, one must identify the sequences that are not correct.
I scoured pg_catalog and friends and cannot identify where PostgreSQL
exposes the link between the "id" and sequence columns. We only
identified the column in error by getting exceptions in the code that
was using <instance>.pk. Once the errant columns are found:

    ALTER SEQUENCE nut_food_id_seq OWNED BY nut_food.id;

must be run for each sequence/table/column. Without this,
pg_get_serial_sequence('"table_name"', 'column_name") returns NULL.

When Django creates tables or one has tables set up with a true SERIAL
column, the above is not needed. It's *only* when the "serial" is
manually constructed, such as from legacy or external databases.

This may be useful to note in the Release Notes for 1.3 as a backwards
incompatible change.

b) The last_insert_id method in the postgresql backend will silently
fail for any expected sequences and return None.
pg_get_serial_sequence() returns NULL when it cannot find a sequence,
and currval() returns NULL as well when passed NULL.

def last_insert_id(self, cursor, table_name, pk_name):
    cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))"
% (table_name, pk_name))
    last_id = cursor.fetchone()[0]
    if last_id is None:
        raise IntegrityError("Valid sequence not found for %s.%s." %
(table_name, pk_name))
    return last_id

would at least make this (and future sequence issues) at least visible
instead of silently failing.

Regards,

Eric

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to