bug? missing foreign key constraints in SQL

19 views
Skip to first unread message

shaunc

unread,
May 20, 2006, 1:44:03 PM5/20/06
to Django developers
Is this the right place to ask about what looks to be a bug? If not,
sorry....

If so, the following code will cause generation of SQL that is missing
constraints:
-----------------------------------------------------------------------------------
# in project 'test'
from django.db.models import (
Model, ForeignKey
)

# Create your models here.


class Retrieval( Model ):
pass

class Abs( Model ):
retrieval = ForeignKey( Retrieval )
invalidatedby = ForeignKey(
Retrieval, related_name = 'invalidates', null = True )


class A1( Abs ):
pass

class A2( Abs ):
pass
----------------------------------------------------------------------------------
C:\...>python manage.py sqlall test
BEGIN;
CREATE TABLE "test_a1" (
"id" serial NOT NULL PRIMARY KEY,
"retrieval_id" integer NOT NULL,
"invalidatedby_id" integer NULL
);
CREATE TABLE "test_abs" (
"id" serial NOT NULL PRIMARY KEY,
"retrieval_id" integer NOT NULL,
"invalidatedby_id" integer NULL
);
CREATE TABLE "test_retrieval" (
"id" serial NOT NULL PRIMARY KEY
);
ALTER TABLE "test_abs" ADD CONSTRAINT
"retrieval_id_referencing_test_retrieval_id" FOREIGN KEY (
"retrieval_id") REFERENCES "test_retrieval" ("id");
ALTER TABLE "test_abs" ADD CONSTRAINT
"invalidatedby_id_referencing_test_retrieval_id" FOREIGN K
EY ("invalidatedby_id") REFERENCES "test_retrieval" ("id");
CREATE TABLE "test_a2" (
"id" serial NOT NULL PRIMARY KEY,
"retrieval_id" integer NOT NULL REFERENCES "test_retrieval" ("id"),
"invalidatedby_id" integer NULL REFERENCES "test_retrieval" ("id")
);
CREATE INDEX test_a1_retrieval_id ON "test_a1" ("retrieval_id");
CREATE INDEX test_a1_invalidatedby_id ON "test_a1"
("invalidatedby_id");
CREATE INDEX test_abs_retrieval_id ON "test_abs" ("retrieval_id");
CREATE INDEX test_abs_invalidatedby_id ON "test_abs"
("invalidatedby_id");
CREATE INDEX test_a2_retrieval_id ON "test_a2" ("retrieval_id");
CREATE INDEX test_a2_invalidatedby_id ON "test_a2"
("invalidatedby_id");
COMMIT;
-----------------------------------------------------------------------------------
Note that constaints of for test_a1 are missing.

NB whether and how this bug happens is highly senstive to the class
names in models.py -- presumably because somewhere the module
dictionary is being iterated through and whether something is a
"forward reference" requiring ALTER TABLEs or a "backward reference"
just requiring constraints in the delcarations depends on the hash
codes for the class names.

But the bottom line is that only one set of ALTER TABLESs can be
generated in this situation, where we might need more than one.

Thanks for help or tips if I'm doing something wrong

- Shaun

shaunc

unread,
May 20, 2006, 4:22:07 PM5/20/06
to Django developers
Ok
django.core.management:108:
---------------------------------------------------------
pending_references.update(references)
---------------------------------------------------------
needs to be replaced by something like:
---------------------------------------------------------
for refto, refs in references.iteritems():
oldrefs = pending_references.get( refto, None )
if oldrefs is not None:
oldrefs.extend( refs )
else:
pending_references[ refto ] = copy.copy( refs )
---------------------------------------------------------
because otherwise pending reference from previous referers are
overwritten.

- Shaun

shaunc

unread,
May 20, 2006, 6:16:59 PM5/20/06
to Django developers
Ok, perhaps slightly more pythonic would be:

for refto, refs in references.iteritems():

try:
pending_references[ refto ].extend( refs )
except KeyError:


pending_references[ refto ] = copy.copy( refs )


- Shaun

Malcolm Tredinnick

unread,
May 20, 2006, 9:08:13 PM5/20/06
to django-d...@googlegroups.com
Hi Shaun,

On Sat, 2006-05-20 at 10:44 -0700, shaunc wrote:
> Is this the right place to ask about what looks to be a bug? If not,
> sorry....
>
> If so, the following code will cause generation of SQL that is missing
> constraints:

[... informative example snipped ...]

> But the bottom line is that only one set of ALTER TABLESs can be
> generated in this situation, where we might need more than one.

Nice debugging (and thanks for the solution in subsequent emails as
well). I think this is the same problem as was reported in ticket #1968
(http://code.djangoproject.com/ticket/1928 ), so I've added a pointer to
this thread to the bottom of that ticket -- since you have gone deeper
than the original report. When somebody gets a chance to review this,
your work should help.

Regards,
Malcolm

Reply all
Reply to author
Forward
0 new messages