Opened 6 years ago

Closed 6 years ago

#29283 closed Bug (invalid)

Difference between 'apps.get_model' and 'import' in migration

Reported by: bronvic Owned by: nobody
Component: Database layer (models, ORM) Version: 1.11
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

HTR:

I have a model UserProfile which looks like this:

class UserProfile(VStandardModel):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, default=None)
    mail = models.TextField(null=True, default=None, unique=True)

And I want to make migration which will do two things:

  1. Change user field to user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=False)
  2. If user was None set a user with an email

So I wrote a migration:

from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth import get_user_model

import django.db.models.deletion


def empty_users(apps, schema_editor):
    UserProfile = apps.get_model('main', 'UserProfile')
    model_user = get_user_model()

    for profile in UserProfile.objects.all().only('user', 'mail'):
        if profile.user is None:
            try:
                profile.user = model_user.objects.get(email=profile.mail)
            except model_user.DoesNotExist:
                try:
                    profile.user = model_user.objects.create(email=profile.mail, is_active=False)
                except Exception as err:
                    print(err)

            profile.save()


class Migration(migrations.Migration):

    dependencies = [
        ('main', '0066_auto_20180222_1954'),
    ]

    operations = [
        migrations.RunPython(empty_users, reverse_code=migrations.RunPython.noop),
        migrations.AlterField(
            model_name='userprofile',
            name='user',
            field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
        ),
    ]

And, as you see, I emphasized an error in except Exception as err:. It is: Cannot assign "<User: >": "UserProfile.user" must be a "User" instance..

But if I change UserProfile = apps.get_model('main', 'UserProfile') to from main.models import UserProfile migration will pass.

Change History (1)

comment:1 by Simon Charette, 6 years ago

Resolution: invalid
Status: newclosed

Hello there,

Without going into all the details you can't mix migration defined models with application defined ones. When writing RunPython executors you must always use the provided apps.get_model method to retrieve models. In your particular case get_user_model() is going to return an application defined model class and not a migration one; you should use apps.get_model(settings.AUTH_USER_MODEL) instead.

In there future please avoid using this ticket tracker as a support channel TicketClosingReasons/UseSupportChannels.

Note: See TracTickets for help on using tickets.
Back to Top