#22931: Migrations cannot rename intermediate models
-------------------------------------+-------------------------------------
     Reporter:  JockeTF              |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Migrations           |                  Version:  1.7-rc-2
     Severity:  Normal               |               Resolution:
     Keywords:  migrations migrate   |             Triage Stage:  Accepted
  makemigrations rename              |      Needs documentation:  0
  intermediate model                 |  Patch needs improvement:  0
    Has patch:  0                    |                    UI/UX:  0
  Needs tests:  0                    |
Easy pickings:  0                    |
-------------------------------------+-------------------------------------
Changes (by JockeTF):

 * status:  closed => new
 * version:  1.7-rc-1 => 1.7-rc-2
 * resolution:  fixed =>


Comment:

 I am still affected by this issue. It appears to affect 1.7c2, 1.7.x,
 master, commit 015496539247b24c73b163f279ae8c8d3ccefc4c, and commit
 d1c08d4758998318eb1a881a3963b63bc89435b8. I have included the steps I took
 to reproduce the issue.

 Start a new application called 'rename' in Django 1.7c2 with two models.

 {{{#!python
 from django.db import models
 from django.conf import settings


 class Channel(models.Model):
     name = models.CharField(max_length=128)
     subscribers = models.ManyToManyField(settings.AUTH_USER_MODEL,
 through='Subscriber', related_name='subscriptions')
     date_created = models.DateTimeField(auto_now_add=True)


 class Subscriber(models.Model):
     user = models.ForeignKey(settings.AUTH_USER_MODEL)
     channel = models.ForeignKey(Channel)
     date_subscribed = models.DateTimeField(auto_now_add=True)

     class Meta():
         unique_together = ('user', 'channel')
 }}}

 Make migrations.

 {{{#!python
 $ python3 manage.py makemigrations
 Migrations for 'rename':
   0001_initial.py:
     - Create model Channel
     - Create model Subscriber
     - Add field subscribers to channel
     - Add field channel to subscriber
     - Add field user to subscriber
     - Alter unique_together for subscriber (1 constraint(s))
 }}}

 Change the name of the subscriber model. Make sure to also update the
 subscribers field to reflect the change.

 {{{#!python
 from django.db import models
 from django.conf import settings


 class Channel(models.Model):
     name = models.CharField(max_length=128)
     subscribers = models.ManyToManyField(settings.AUTH_USER_MODEL,
 through='Subscribe', related_name='subscriptions')
     date_created = models.DateTimeField(auto_now_add=True)


 class Subscribe(models.Model):
     user = models.ForeignKey(settings.AUTH_USER_MODEL)
     channel = models.ForeignKey(Channel)
     date_subscribed = models.DateTimeField(auto_now_add=True)

     class Meta():
         unique_together = ('user', 'channel')
 }}}

 Make migrations.

 {{{#!python
 $ python3 manage.py makemigrations
 Migrations for 'rename':
   0002_auto_20140729_0822.py:
     - Create model Subscribe
     - Alter unique_together for subscribe (1 constraint(s))
     - Alter unique_together for subscriber (0 constraint(s))
     - Remove field channel from subscriber
     - Remove field user from subscriber
     - Delete model Subscriber
     - Alter field subscribers on channel
 }}}

 Django failed to detect the rename (perhaps due to some other bug).
 Replace the automatically generated migration with one generated by Django
 1.7b4. I cannot say whether or not this migration would still be valid,
 but I have no other way of generating a proper migration at the moment.

 {{{#!python
 from django.db import models, migrations
 from django.conf import settings


 class Migration(migrations.Migration):
     dependencies = [
         ('rename', '0001_initial'),
     ]

     operations = [
         migrations.RenameModel(
             old_name='Subscriber',
             new_name='Subscribe',
         ),
         migrations.AlterField(
             model_name='channel',
             name='subscribers',
             field=models.ManyToManyField(through='rename.Subscribe',
 to=settings.AUTH_USER_MODEL),
         ),
     ]
 }}}

 Make migrations detects no further changes.

 {{{#!python
 $ python3 manage.py makemigrations
 No changes detected
 }}}

 Migrate.

 {{{#!python
 $ python3 manage.py migrate
 Operations to perform:
   Apply all migrations: sessions, contenttypes, admin, auth, rename
 Running migrations:
   Applying contenttypes.0001_initial... OK
   Applying auth.0001_initial... OK
   Applying admin.0001_initial... OK
   Applying rename.0001_initial... OK
   Applying rename.0002_auto_20140729_0822...Traceback (most recent call
 last):
   File "/usr/local/lib/python3.4/dist-packages/django/apps/config.py",
 line 158, in get_model
     return self.models[model_name.lower()]
 KeyError: 'subscriber'

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/state.py", line 79, in render
     model = self.apps.get_model(lookup_model[0], lookup_model[1])
   File "/usr/local/lib/python3.4/dist-packages/django/apps/registry.py",
 line 202, in get_model
     return self.get_app_config(app_label).get_model(model_name.lower())
   File "/usr/local/lib/python3.4/dist-packages/django/apps/config.py",
 line 161, in get_model
     "App '%s' doesn't have a '%s' model." % (self.label, model_name))
 LookupError: App 'rename' doesn't have a 'subscriber' model.

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/__init__.py", line 385, in
 execute_from_command_line
     utility.execute()
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/__init__.py", line 377, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/base.py", line 288, in run_from_argv
     self.execute(*args, **options.__dict__)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/base.py", line 337, in execute
     output = self.handle(*args, **options)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/commands/migrate.py", line 160, in handle
     executor.migrate(targets, plan, fake=options.get("fake", False))
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/executor.py", line 63, in migrate
     self.apply_migration(migration, fake=fake)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/executor.py", line 97, in apply_migration
     migration.apply(project_state, schema_editor)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/migration.py", line 107, in apply
     operation.database_forwards(self.app_label, schema_editor,
 project_state, new_state)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/operations/models.py", line 141, in
 database_forwards
     new_apps = to_state.render()
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/state.py", line 89, in render
     model=lookup_model,
 ValueError: Lookup failed for model referenced by field
 rename.Channel.subscribers: rename.Subscriber
 }}}

 I also tried to change the order of the operations.

 {{{#!python
 from django.db import models, migrations
 from django.conf import settings


 class Migration(migrations.Migration):
     dependencies = [
         ('rename', '0001_initial'),
     ]

     operations = [
         migrations.AlterField(
             model_name='channel',
             name='subscribers',
             field=models.ManyToManyField(through='rename.Subscribe',
 to=settings.AUTH_USER_MODEL),
         ),
         migrations.RenameModel(
             old_name='Subscriber',
             new_name='Subscribe',
         ),
     ]
 }}}

 This results in a slightly different exception.

 {{{#!python
 $ rm db.sqlite3
 $ python3 manage.py migrate
 Operations to perform:
   Apply all migrations: rename, admin, auth, contenttypes, sessions
 Running migrations:
   Applying contenttypes.0001_initial... OK
   Applying auth.0001_initial... OK
   Applying admin.0001_initial... OK
   Applying rename.0001_initial... OK
   Applying rename.0002_auto_20140729_0822...Traceback (most recent call
 last):
   File "/usr/local/lib/python3.4/dist-packages/django/apps/config.py",
 line 158, in get_model
     return self.models[model_name.lower()]
 KeyError: 'subscribe'

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/state.py", line 79, in render
     model = self.apps.get_model(lookup_model[0], lookup_model[1])
   File "/usr/local/lib/python3.4/dist-packages/django/apps/registry.py",
 line 202, in get_model
     return self.get_app_config(app_label).get_model(model_name.lower())
   File "/usr/local/lib/python3.4/dist-packages/django/apps/config.py",
 line 161, in get_model
     "App '%s' doesn't have a '%s' model." % (self.label, model_name))
 LookupError: App 'rename' doesn't have a 'subscribe' model.

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/__init__.py", line 385, in
 execute_from_command_line
     utility.execute()
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/__init__.py", line 377, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/base.py", line 288, in run_from_argv
     self.execute(*args, **options.__dict__)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/base.py", line 337, in execute
     output = self.handle(*args, **options)
   File "/usr/local/lib/python3.4/dist-
 packages/django/core/management/commands/migrate.py", line 160, in handle
     executor.migrate(targets, plan, fake=options.get("fake", False))
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/executor.py", line 63, in migrate
     self.apply_migration(migration, fake=fake)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/executor.py", line 91, in apply_migration
     if self.detect_soft_applied(migration):
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/executor.py", line 134, in
 detect_soft_applied
     project_state = self.loader.project_state((migration.app_label,
 migration.name), at_end=True)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/loader.py", line 268, in project_state
     return self.graph.make_state(nodes=nodes, at_end=at_end,
 real_apps=list(self.unmigrated_apps))
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/graph.py", line 147, in make_state
     project_state = self.nodes[node].mutate_state(project_state)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/migration.py", line 76, in mutate_state
     operation.state_forwards(self.app_label, new_state)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/operations/models.py", line 117, in
 state_forwards
     apps = state.render(skip_cache=True)
   File "/usr/local/lib/python3.4/dist-
 packages/django/db/migrations/state.py", line 89, in render
     model=lookup_model,
 ValueError: Lookup failed for model referenced by field
 rename.Channel.subscribers: rename.Subscribe
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/22931#comment:7>
Django <https://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 unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.2fe98c53000af5e93f9f424c3a6a7cfe%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to