#3779: Problem with ManyToManyFields and syncdb
---------------------------------------------------+------------------------
Reporter: Ben Slavin <[EMAIL PROTECTED]> | Owner: adrian
Status: new | Component: Core
framework
Version: SVN | Keywords:
Stage: Unreviewed | Has_patch: 0
---------------------------------------------------+------------------------
The creation of !ManyToMany tables in the database through syncdb is prone
to failure, and depends on the ordering of {{{INSTALLED_APPS}}} in
{{{settings.py}}}.
{{{manage.py syncdb}}} uses a deferral system ({{{seen_models}}} and
{{{pending_references}}}) to ensure proper setup of model tables in the
database. This allows the tables to be created without references, and
constraints to be added after the related tables exist.
Currently, the creation of {{{ManyToMany}}} tables (in
{{{django.core.management._get_many_to_many_sql_for_model}}}) does not use
a deferral mechanism, and will fail to create the tables properly. If the
models are loaded in the right order, this isn't an issue; however, if the
they are loaded in reverse order and the database is strict about
enforcing references (PostgreSQL), this is problematic.
'''Note:''' This doesn't impact MySQL (MyISAM) or sqlite because of the
way they handle references -- they don't.
Here's an example:
{{{bar/models.py}}}
{{{
#!python
from django.db import models
from myproj.foo.models import Foo
class Bar(models.Model):
foos = models.ManyToManyField(Foo)
}}}
{{{foo/models.py}}}
{{{
#!python
from django.db import models
class Foo(models.Model):
a = models.IntegerField()
}}}
{{{settings.py}}} excerpt ('''working''' version)
{{{
#!python
INSTALLED_APPS = ('m2m.foo','m2m.bar')
}}}
{{{settings.py}}} excerpt ('''non-working''' version)
{{{
#!python
INSTALLED_APPS = ('m2m.bar','m2m.foo')
}}}
{{{manage.py syncdb}}} output for non-working version
{{{
Creating table bar_bar
Traceback (most recent call last):
File "./manage.py", line 11, in ?
execute_manager(settings)
File "/usr/lib/python2.4/site-packages/django/core/management.py", line
1666, in execute_manager
execute_from_command_line(action_mapping, argv)
File "/usr/lib/python2.4/site-packages/django/core/management.py", line
1565, in execute_from_command_line
action_mapping[action](int(options.verbosity), options.interactive)
File "/usr/lib/python2.4/site-packages/django/core/management.py", line
543, in syncdb
cursor.execute(statement)
File "/usr/lib/python2.4/site-packages/django/db/backends/util.py", line
12, in execute
return self.cursor.execute(sql, params)
File "/usr/lib/python2.4/site-
packages/django/db/backends/postgresql/base.py", line 43, in execute
return self.cursor.execute(sql, [smart_basestring(p, self.charset) for
p in params])
psycopg.ProgrammingError: ERROR: relation "foo_foo" does not exist
CREATE TABLE "bar_bar_foos" (
"id" serial NOT NULL PRIMARY KEY,
"bar_id" integer NOT NULL REFERENCES "bar_bar" ("id") DEFERRABLE
INITIALLY DEFERRED,
"foo_id" integer NOT NULL REFERENCES "foo_foo" ("id") DEFERRABLE
INITIALLY DEFERRED,
UNIQUE ("bar_id", "foo_id")
);
}}}
The problem is that "foo_id" should be "{{{integer NOT NULL}}}" and an
{{{ALTER TABLE}}} statement should be issued for {{{bar_bar_foos}}} after
the {{{foo_foo}}} table is created, rather than trying to create the
reference initially.
--
Ticket URL: <http://code.djangoproject.com/ticket/3779>
Django Code <http://code.djangoproject.com/>
The web framework for perfectionists with deadlines
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---