Opened 3 years ago
Closed 2 years ago
#33566 closed Bug (needsinfo)
Issue with migrations after upgrading Django 2 to Django 3.2.
Reported by: | Ismael Jerez | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | 3.2 |
Severity: | Normal | Keywords: | orm, migrate, makemigrations, database, migrations, migration |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hi,
I recently upgraded from Django 2 to Django 3.2.
Everything works fine but when I execute “migrate” as a manage.py command, it always says “Your models in app(s): ‘admin’, ‘auth’, ‘base’, ‘contenttypes’, ‘sessions’ have changes that are not yet reflected in a migration, and so won’t be applied.
Run ‘manage.py makemigrations’ to make new migrations, and then re-run ‘manage.py migrate’ to apply them.”
If I execute “makemigrations” commands I always get “No changes detected”.
I downgrade to Django2, the message is gone.
I have every mentioned app on my INSTALLED_APPS variable in settings. As you can see only ‘base’ app is one of mine, the rest are default Django apps.
I am using Oracle 19 database that can not be recreated.
I hope you can help me or give me some ideas of what is happening and why am I receiving that message from “migrate” command.
Thank you in advance,
Ismael.
Change History (5)
comment:1 by , 3 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
comment:2 by , 2 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
Hi again:
Sorry, it's been a while. I cannot share my code due to confidentiality, but I think I found a solution.
I was debugging migrate command to see what changes are being detected. Then, I have called write_migration_files(changes) from makemigrations command using the changes detected before. After this, I have new migrations created for the mentioned apps. Most of the changes are only verbose_name related (Spanish translations) and minor updates, so I think it should be safe to migrate.
The question is: why did migrate command detect these changes (see below) but makemigrations did not? I think both changes autodetector should work the same way to avoid problems like this one.
These are the changes detected by migrate command (but not by makemigrations) related to Django default apps:
admin app:
# Generated by Django 3.2.13 on 2022-06-08 07:39 from django.db import migrations, models import django.db.models.deletion import django.utils.timezone class Migration(migrations.Migration): dependencies = [ ('base', '0012_auto_20220608_0939'), ('contenttypes', '0003_auto_20220608_0939'), ('admin', '0003_logentry_add_action_flag_choices'), ] operations = [ migrations.AlterModelOptions( name='logentry', options={'ordering': ['-action_time'], 'verbose_name': 'entrada de registro', 'verbose_name_plural': 'entradas de registro'}, ), migrations.AlterField( model_name='logentry', name='action_flag', field=models.PositiveSmallIntegerField(choices=[(1, 'Añadido'), (2, 'Modificar'), (3, 'Borrado')], verbose_name='marca de acción'), ), migrations.AlterField( model_name='logentry', name='action_time', field=models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='hora de la acción'), ), migrations.AlterField( model_name='logentry', name='change_message', field=models.TextField(blank=True, verbose_name='mensaje de cambio'), ), migrations.AlterField( model_name='logentry', name='content_type', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.contenttype', verbose_name='tipo de contenido'), ), migrations.AlterField( model_name='logentry', name='object_id', field=models.TextField(blank=True, null=True, verbose_name='id del objeto'), ), migrations.AlterField( model_name='logentry', name='object_repr', field=models.CharField(max_length=200, verbose_name='repr del objeto'), ), migrations.AlterField( model_name='logentry', name='user', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.ucauser', verbose_name='usuario'), ), ]
auth app:
# Generated by Django 3.2.13 on 2022-06-08 07:39 import django.contrib.auth.validators from django.db import migrations, models import django.db.models.deletion import django.utils.timezone class Migration(migrations.Migration): dependencies = [ ('contenttypes', '0003_auto_20220608_0939'), ('auth', '0012_alter_user_first_name_max_length'), ] operations = [ migrations.AlterModelOptions( name='group', options={'verbose_name': 'grupo', 'verbose_name_plural': 'grupos'}, ), migrations.AlterModelOptions( name='permission', options={'ordering': ['content_type__app_label', 'content_type__model', 'codename'], 'verbose_name': 'permiso', 'verbose_name_plural': 'permisos'}, ), migrations.AlterModelOptions( name='user', options={'verbose_name': 'usuario', 'verbose_name_plural': 'usuarios'}, ), migrations.AlterField( model_name='group', name='name', field=models.CharField(max_length=150, unique=True, verbose_name='nombre'), ), migrations.AlterField( model_name='group', name='permissions', field=models.ManyToManyField(blank=True, to='auth.Permission', verbose_name='permisos'), ), migrations.AlterField( model_name='permission', name='codename', field=models.CharField(max_length=100, verbose_name='nombre en código'), ), migrations.AlterField( model_name='permission', name='content_type', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='tipo de contenido'), ), migrations.AlterField( model_name='permission', name='name', field=models.CharField(max_length=255, verbose_name='nombre'), ), migrations.AlterField( model_name='user', name='date_joined', field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='fecha de alta'), ), migrations.AlterField( model_name='user', name='email', field=models.EmailField(blank=True, max_length=254, verbose_name='dirección de correo electrónico'), ), migrations.AlterField( model_name='user', name='first_name', field=models.CharField(blank=True, max_length=150, verbose_name='nombre'), ), migrations.AlterField( model_name='user', name='groups', field=models.ManyToManyField(blank=True, help_text='Los grupos a los que pertenece este usuario. Un usuario tendrá todos los permisos asignados a cada uno de sus grupos.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='grupos'), ), migrations.AlterField( model_name='user', name='is_active', field=models.BooleanField(default=True, help_text='Indica si el usuario debe ser tratado como activo. Desmarque esta opción en lugar de borrar la cuenta.', verbose_name='activo'), ), migrations.AlterField( model_name='user', name='is_staff', field=models.BooleanField(default=False, help_text='Indica si el usuario puede entrar en este sitio de administración.', verbose_name='es staff'), ), migrations.AlterField( model_name='user', name='is_superuser', field=models.BooleanField(default=False, help_text='Indica que este usuario tiene todos los permisos sin asignárselos explícitamente.', verbose_name='estado de superusuario'), ), migrations.AlterField( model_name='user', name='last_login', field=models.DateTimeField(blank=True, null=True, verbose_name='último inicio de sesión'), ), migrations.AlterField( model_name='user', name='last_name', field=models.CharField(blank=True, max_length=150, verbose_name='apellidos'), ), migrations.AlterField( model_name='user', name='password', field=models.CharField(max_length=128, verbose_name='contraseña'), ), migrations.AlterField( model_name='user', name='user_permissions', field=models.ManyToManyField(blank=True, help_text='Permisos específicos para este usuario.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='permisos de usuario'), ), migrations.AlterField( model_name='user', name='username', field=models.CharField(error_messages={'unique': 'Ya existe un usuario con este nombre.'}, help_text='Requerido. 150 carácteres como máximo. Únicamente letras, dígitos y @/./+/-/_ ', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='nombre de usuario'), ), ]
contenttypes app:
# Generated by Django 3.2.13 on 2022-06-08 07:39 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ] operations = [ migrations.AlterModelOptions( name='contenttype', options={'verbose_name': 'tipo de contenido', 'verbose_name_plural': 'tipos de contenido'}, ), migrations.AlterField( model_name='contenttype', name='model', field=models.CharField(max_length=100, verbose_name='nombre de la clase modelo de python'), ), ]
sessions app:
# Generated by Django 3.2.13 on 2022-06-08 07:39 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('sessions', '0001_initial'), ] operations = [ migrations.AlterModelOptions( name='session', options={'verbose_name': 'sesión', 'verbose_name_plural': 'sesiones'}, ), migrations.AlterField( model_name='session', name='expire_date', field=models.DateTimeField(db_index=True, verbose_name='fecha de caducidad'), ), migrations.AlterField( model_name='session', name='session_data', field=models.TextField(verbose_name='datos de sesión'), ), migrations.AlterField( model_name='session', name='session_key', field=models.CharField(max_length=40, primary_key=True, serialize=False, verbose_name='clave de sesión'), ), ]
comment:3 by , 2 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Thanks for the follow-up.
How are you setting language for your project? Do you have any customisations there at boot-up?
I'm struggling to get the options translated into Spanish at all (in migrate
or makemigrations
):
options={'verbose_name': 'grupo', 'verbose_name_plural': 'grupos'},
This is because both migrate
and makemigrations
use the private @no_translations
decorator (src).
The only way I've managed to reproduce your error is by disabling that and then adding LANGUAGE_CODE = "es"
to settings.
However if I do that, the change applies equally to makemigrations
.
I was able to reproduce that with a stock fresh project created with startproject
, so you should be able to do the same, but it looks like you must have some customisation in play that you've not specified here. If you can include it in a minimal sample project, happy to have a look.
comment:4 by , 2 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
Hi:
Thanks you for your reply. I don't have any customisation. About internationalisation this is my setting:
LANGUAGE_CODE = 'es-es' TIME_ZONE = 'Europe/Madrid' USE_I18N = True USE_L10N = True USE_TZ = True
I test it removing these options so makemigrations generates new migrations like reverting verbose_name to English but anyway when I run migrate after that I still getting the message about changes not reflected in a migration...
I don't think the rest of my variables could take effect on migrations.
My last try:
I edited makemigrations command commenting some lines just as migrate command:
autodetector = MigrationAutodetector( loader.project_state(), ProjectState.from_apps(apps), # questioner, )
changes = autodetector.changes( graph=loader.graph, # trim_to_apps=app_labels or None, # convert_apps=app_labels or None, # migration_name=self.migration_name, )
After this and removing internationalisation settings, it generates all these migrations:
Migrations for 'contenttypes': venv2\lib\site-packages\django\contrib\contenttypes\migrations\0004_auto_20220610_0826.py - Change Meta options on contenttype - Alter field model on contenttype Migrations for 'sessions': venv2\lib\site-packages\django\contrib\sessions\migrations\0003_auto_20220610_0826.py - Change Meta options on session - Alter field expire_date on session - Alter field session_data on session - Alter field session_key on session Migrations for 'auth': venv2\lib\site-packages\django\contrib\auth\migrations\0014_auto_20220610_0826.py - Change Meta options on group - Change Meta options on permission - Change Meta options on user - Alter field name on group - Alter field permissions on group - Alter field codename on permission - Alter field content_type on permission - Alter field name on permission - Alter field date_joined on user - Alter field email on user - Alter field first_name on user - Alter field groups on user - Alter field is_active on user - Alter field is_staff on user - Alter field is_superuser on user - Alter field last_login on user - Alter field last_name on user - Alter field password on user - Alter field user_permissions on user - Alter field username on user Migrations for 'admin': venv2\lib\site-packages\django\contrib\admin\migrations\0005_auto_20220610_0826.py - Change Meta options on logentry - Alter field action_flag on logentry - Alter field action_time on logentry - Alter field change_message on logentry - Alter field content_type on logentry - Alter field object_id on logentry - Alter field object_repr on logentry - Alter field user on logentry
These are the last three migrations generated on auth app:
from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('auth', '0009_alter_user_last_name_max_length'), ] operations = [ migrations.AlterField( model_name='group', name='name', field=models.CharField(max_length=150, unique=True, verbose_name='name'), ), ]
import sys from django.core.management.color import color_style from django.db import IntegrityError, migrations, transaction from django.db.models import Q WARNING = """ A problem arose migrating proxy model permissions for {old} to {new}. Permission(s) for {new} already existed. Codenames Q: {query} Ensure to audit ALL permissions for {old} and {new}. """ def update_proxy_model_permissions(apps, schema_editor, reverse=False): """ Update the content_type of proxy model permissions to use the ContentType of the proxy model. """ style = color_style() Permission = apps.get_model('auth', 'Permission') ContentType = apps.get_model('contenttypes', 'ContentType') alias = schema_editor.connection.alias for Model in apps.get_models(): opts = Model._meta if not opts.proxy: continue proxy_default_permissions_codenames = [ '%s_%s' % (action, opts.model_name) for action in opts.default_permissions ] permissions_query = Q(codename__in=proxy_default_permissions_codenames) for codename, name in opts.permissions: permissions_query = permissions_query | Q(codename=codename, name=name) content_type_manager = ContentType.objects.db_manager(alias) concrete_content_type = content_type_manager.get_for_model(Model, for_concrete_model=True) proxy_content_type = content_type_manager.get_for_model(Model, for_concrete_model=False) old_content_type = proxy_content_type if reverse else concrete_content_type new_content_type = concrete_content_type if reverse else proxy_content_type try: with transaction.atomic(using=alias): Permission.objects.using(alias).filter( permissions_query, content_type=old_content_type, ).update(content_type=new_content_type) except IntegrityError: old = '{}_{}'.format(old_content_type.app_label, old_content_type.model) new = '{}_{}'.format(new_content_type.app_label, new_content_type.model) sys.stdout.write(style.WARNING(WARNING.format(old=old, new=new, query=permissions_query))) def revert_proxy_model_permissions(apps, schema_editor): """ Update the content_type of proxy model permissions to use the ContentType of the concrete model. """ update_proxy_model_permissions(apps, schema_editor, reverse=True) class Migration(migrations.Migration): dependencies = [ ('auth', '0010_alter_group_name_max_length'), ('contenttypes', '0002_remove_content_type_name'), ] operations = [ migrations.RunPython(update_proxy_model_permissions, revert_proxy_model_permissions), ]
from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('auth', '0011_update_proxy_permissions'), ] operations = [ migrations.AlterField( model_name='user', name='first_name', field=models.CharField(blank=True, max_length=150, verbose_name='first name'), ), ]
I can paste you the rest of the migrations if you need them.
Just in case, remember I was migrating from Django 2 to Django 3.
These are my installed pip packages, just to be sure any of these are not affecting it:
django==3.2.13 django-debug-toolbar cx-Oracle==7.3.0 django-braces django-tinymce==2.8.0 suds-jurko==0.6 django-bootstrap3 django-wkhtmltopdf==3.3.0 xlwt==1.3.0 ftfy==5.7 psycopg2 selenium django-nocaptcha-recaptcha==0.0.20 zeep
Thanks you in advance,
Ismael.
comment:5 by , 2 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Thanks for the reply Ismael.
I test it removing these options so makemigrations generates new migrations like reverting verbose_name to English but anyway when I run migrate after that I still getting the message about changes not reflected in a migration...
There are two things here I can't quite make sense of:
I test it removing these options so makemigrations generates new migrations like reverting verbose_name to English...
So this implies the @no_translations
decorator is not working, so there must be some customisation in your project affecting that.
... anyway when I run migrate after that I still getting the message about changes not reflected in a migration...
As per my previous comment, I can get both commands to apply translations but not just one of them, as you're seeing here. (Again, there must be a customisation somewhere in your setup, one would think)
Can you provide a sample project, created using startproject
and adding just enough, to recreate the issue? Otherwise it's hard to see where the error could be.
Hi, I don't think you've explained the issue in enough detail to confirm a bug in Django. Can you provide a sample project showing a fault in Django?