#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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
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