Ticket #436 (closed defect: fixed)

Opened 5 years ago

Last modified 3 years ago

Migration Fails with Proxy Model

Reported by: physicsrob@… Owned by: andrew
Priority: major Milestone: 0.7.1
Component: commands Version: 0.7
Keywords: Cc:

Description

It appears that there is a problem migrating applications that have a model with a foreignkey pointing to a proxy for django's User model.

Here is the example I'm trying with:

class MyUser?(User):

class Meta:

proxy=True

class MyModel?(models.Model):

user = models.ForeignKey?(MyUser?)

If you try to create a migration for this application you will get a failure:
south.exceptions.ORMBaseNotIncluded: Cannot find ORM base auth.user

I'm very new to south, so excuse my poor explanation, but it appears that the problem is in the migration's 'models' dictionary. It seems that there needs to be an entry for 'auth.user', but that never gets added.

Fortunately there is a workaround. If you add a dummy table to the application with a ForeignKey? on the User, south will properly add the 'auth.user' entry to the migrations 'models' dictionary.

e.g.:

class MyWorkaround?(models.Model):

user = models.ForeignKey?(User)

Attachments

south_fix436.patch (858 bytes) - added by physicsrob@… 5 years ago.
patch to fix problem
south_fix436_second_try.patch (858 bytes) - added by physicsrob@… 5 years ago.
patch to fix problem

Change History

Changed 5 years ago by physicsrob@…

patch to fix problem

comment:1 Changed 5 years ago by physicsrob@…

I've created a patch that fixes this problem. Please review it thoroughly to make sure it makes sense.

Basically what I found was that model_dependencies (in freezer.py) was not correctly including dependencies to base classes. It was only adding base classes as dependencies if the base class is an instance of models.Model. This will only be true if the base class IS models.Model.

I updated the code by essentially replacing isinstance with issubclass. So now any base classes that are models will be included as dependencies. Which I believe is the correct behavior.

Let me know your thoughts!

Cheers,
Rob

Changed 5 years ago by physicsrob@…

patch to fix problem

comment:2 Changed 5 years ago by physicsrob@…

Oops! The first patch I attached had a mistake. This one should be good!

comment:3 Changed 4 years ago by andrew

  • Status changed from new to closed
  • Resolution set to fixed
  • Milestone set to 0.7.1

Yes, that's exactly the fix, thanks! Committed in [0505afae2906].

comment:4 Changed 4 years ago by kostia <kostia.lopuhin@…>

There is another related problem, not shure if it's worth a separate ticket: when there is a ManyToMany? field, that references proxy model:

If you define models in southtest application like this:


class ModelA(models.Model):
    pass

class ProxyModel(ModelA):
    class Meta:
        proxy = True

class ModelB(models.Model):
    modela_list = models.ManyToManyField(ProxyModel)

than create initial migration, you will get the following error when trying to apply it:

kostia@kostia-laptop:~/chtd/mcxgp$ python manage.py schemamigration southtest --initial
Creating migrations directory at '/home/kostia/chtd/mcxgp/southtest/migrations'...
Creating __init__.py in '/home/kostia/chtd/mcxgp/southtest/migrations'...
 + Added model southtest.ModelA
 + Added model southtest.ModelB
 + Added M2M table for modela_list on southtest.ModelB
Created 0001_initial.py. You can now apply this migration with: ./manage.py migrate southtest

kostia@kostia-laptop:~/chtd/mcxgp$ python manage.py migrate southtest
Running migrations for southtest:
 - Migrating forwards to 0001_initial.
 > southtest:0001_initial
Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    execute_manager(settings)
  File "/home/kostia/chtd/lib/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/home/kostia/chtd/lib/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/kostia/chtd/lib/django/core/management/base.py", line 195, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/kostia/chtd/lib/django/core/management/base.py", line 222, in execute
    output = self.handle(*args, **options)
  File "/home/kostia/chtd/lib/south/management/commands/migrate.py", line 109, in handle
    ignore_ghosts = ignore_ghosts,
  File "/home/kostia/chtd/lib/south/migration/__init__.py", line 202, in migrate_app
    success = migrator.migrate_many(target, workplan, database)
  File "/home/kostia/chtd/lib/south/migration/migrators.py", line 220, in migrate_many
    result = migrator.__class__.migrate_many(migrator, target, migrations, database)
  File "/home/kostia/chtd/lib/south/migration/migrators.py", line 291, in migrate_many
    result = self.migrate(migration, database)
  File "/home/kostia/chtd/lib/south/migration/migrators.py", line 125, in migrate
    result = self.run(migration)
  File "/home/kostia/chtd/lib/south/migration/migrators.py", line 99, in run
    return self.run_migration(migration)
  File "/home/kostia/chtd/lib/south/migration/migrators.py", line 82, in run_migration
    south.db.db.execute_deferred_sql()
  File "/home/kostia/chtd/lib/south/db/generic.py", line 168, in execute_deferred_sql
    self.execute(sql)
  File "/home/kostia/chtd/lib/south/db/generic.py", line 134, in execute
    cursor.execute(sql, params)
  File "/home/kostia/chtd/lib/django/db/backends/util.py", line 20, in execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: column "modela_ptr_id" referenced in foreign key constraint does not exist

using python 2.6.5, Django version 1.2 alpha 1 SVN-4476, postgresql-8.4

the problem is in generated migration, specificaly if you change this

        # Adding M2M table for field modela_list on 'ModelB'
        db.create_table('southtest_modelb_modela_list', (
            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
            ('modelb', models.ForeignKey(orm['southtest.modelb'], null=False)),
            ('proxymodel', models.ForeignKey(orm['southtest.proxymodel'], null=False))
        ))
        db.create_unique('southtest_modelb_modela_list', ['modelb_id', 'proxymodel_id'])

to this

        # Adding M2M table for field modela_list on 'ModelB'
        db.create_table('southtest_modelb_modela_list', (
            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
            ('modelb', models.ForeignKey(orm['southtest.modelb'], null=False)),
            ('proxymodel', models.ForeignKey(orm['southtest.modela'], null=False))
        ))
        db.create_unique('southtest_modelb_modela_list', ['modelb_id', 'proxymodel_id'])

(so that relation is with modela, not proxymodel, keeping field names the same) - than the migration runs smoothly. I'm not quite shure that this is a universall and even proper fix, but seems to work for me.

comment:5 follow-up: ↓ 6 Changed 4 years ago by andrew

Yes, that's really worthy of a separate bug - could you re-file it? The fix shouldn't be too hard, I hope.

comment:6 in reply to: ↑ 5 Changed 4 years ago by kostia.lopuhin@…

Replying to andrew:

Yes, that's really worthy of a separate bug - could you re-file it? The fix shouldn't be too hard, I hope.

Thanx! Refiled it as http://south.aeracode.org/ticket/496

comment:7 follow-up: ↓ 8 Changed 3 years ago by benjaoming@…

Hi!

I just tried to add a proxy table for the User model. ./manage.py schemamigration appname then created the following wrong migration script:

        db.create_table('auth_user', (
            ,
        ))

...which I had to comment out. After that, everything worked fine. Am using South 0.7.3.

comment:8 in reply to: ↑ 7 Changed 3 years ago by andrew

Replying to benjaoming@…:

Hi!

I just tried to add a proxy table for the User model. ./manage.py schemamigration appname then created the following wrong migration script:

If you have a problem, please:

  • Re-test using the South development version
  • Open a bug, attaching the models file and the generated migration file
Note: See TracTickets for help on using tickets.