[Django] #29283: Difference between 'apps.get_model' and 'import' in migration

16 views
Skip to first unread message

Django

unread,
Apr 1, 2018, 12:26:42 PM4/1/18
to django-...@googlegroups.com
#29283: Difference between 'apps.get_model' and 'import' in migration
-------------------------------------+-------------------------------------
Reporter: bronvic | Owner: nobody
Type: Bug | Status: new
Component: Database | Version: 1.11
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
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.

--
Ticket URL: <https://code.djangoproject.com/ticket/29283>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Apr 1, 2018, 1:54:36 PM4/1/18
to django-...@googlegroups.com
#29283: Difference between 'apps.get_model' and 'import' in migration
-------------------------------------+-------------------------------------
Reporter: bronvic | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 1.11
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

* status: new => closed
* resolution: => invalid


Comment:

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.

--
Ticket URL: <https://code.djangoproject.com/ticket/29283#comment:1>

Reply all
Reply to author
Forward
0 new messages