Kurt Peek
Kurt Peek

Reputation: 57381

Django missing a migration in the 'auth' app

I'm trying to work on a Django project on a different computer than the one I usually do. However, when trying to run the following migration:

from django.conf import settings
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('auth', '0010_auto_20180727_1345'),
        ('lucy_web', '0183_auto_20180814_1505'),
    ]

    operations = [
        migrations.CreateModel(
            name='GoogleCredentials',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('updated_at', models.DateTimeField(auto_now=True)),
                ('user', models.OneToOneField(limit_choices_to={'is_staff': True}, on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
                ('token', models.CharField(max_length=255, null=True)),
                ('refresh_token', models.CharField(max_length=255, null=True)),
                ('token_uri', models.CharField(max_length=255, null=True)),
                ('client_id', models.CharField(max_length=255, null=True)),
                ('client_secret', models.CharField(max_length=255, null=True)),
                ('scopes', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=255), null=True, size=None)),
            ],
            options={
                'abstract': False,
            },
        ),
    ]

I get this error message:

django.db.migrations.exceptions.NodeNotFoundError: Migration lucy_web.0184_googlecredentials dependencies reference nonexistent parent node ('auth', '0010_auto_20180727_1345')

Following https://groups.google.com/forum/#!topic/django-users/m59NufO1GI8, I went into the django/contrib/auth/migrations directory and found that indeed, there are 9 migrations, but the 10th migration is not there:

Kurts-MacBook-Pro:auth kurtpeek$ ls migrations
0001_initial.py
0002_alter_permission_name_max_length.py
0003_alter_user_email_max_length.py
0004_alter_user_username_opts.py
0005_alter_user_last_login_null.py
0006_require_contenttypes_0002.py
0007_alter_validators_add_error_messages.py
0008_alter_user_username_max_length.py
0009_alter_user_last_name_max_length.py
__init__.py
__pycache__/
Kurts-MacBook-Pro:auth kurtpeek$ pwd
/Users/kurtpeek/.local/share/virtualenvs/lucy-web-oCa8O1zi/lib/python3.7/site-packages/django/contrib/auth

The problem is, I haven't checked the virtual env into version control, and I don't have access to the other computer at the moment. I also feel like I shouldn't have to check in the Django source code for the project, though.

My question is: how did this situation likely come to pass? What I suspect is that it is associated with the way the django.contrib.auth.User model is customized in the project. We have a lucy_web/models/user.py with content similar to the following:

from django.contrib.auth.models import User
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
from auditlog.registry import auditlog
from lucy_web.models import LucyGuide
from crequest.middleware import CrequestMiddleware
from lucy_web.lib import intercom

# overrides built in user to provide reasonable unique constraints
User._meta.get_field('username')._unique = True
# TODO(kayla): fix this, the unique constraint on email doesn't seem to be working in prod
# I suspect the username unique constraint only works because it's the default setting
User._meta.get_field('email')._unique = True


auditlog.register(User)


@property
def family(self):
    if hasattr(self, 'employee_family'):
        return self.employee_family
    elif hasattr(self, 'partner_family'):
        return self.partner_family
    else:
        return None


@property
def is_employee(self):
    return hasattr(self, 'employee_family')


@property
def user_apn(self):
    return self.userapn_set.order_by("created_at").last()


@property
def lucy_guide(self):
    try:
        return self.lucyguide
    except LucyGuide.DoesNotExist:
        return None


def user__str__(self):
    """
    User model's __str__ method.
    We use a different name than '__str__' because dunder names
    are reserved by Python and subject to breakage without warning
    (cf. https://www.python.org/dev/peps/pep-0562/#backwards-compatibility-and-impact-on-performance).
    """
    return f"{self.first_name} {self.last_name}".strip()


@property
def profile(self):
    if hasattr(self, 'user_profile'):
        return self.user_profile
    else:
        return None


@property
def using_app(self):
    if hasattr(self, 'user_profile'):
        return self.user_profile.using_app

    return False


@property
def activation_code(self):
    if hasattr(self, 'user_profile'):
        return self.user_profile.activation_code

    return False


User.add_to_class('family', family)
User.add_to_class('is_employee', is_employee)
User.add_to_class('user_apn', user_apn)
User.add_to_class('lucy_guide', lucy_guide)
User.add_to_class('__str__', user__str__)
User.add_to_class('profile', profile)
User.add_to_class('using_app', using_app)

In short, we use the add_to_class method to add properties to Django's User model. This does not seem to be one of the recommended methods described in https://docs.djangoproject.com/en/2.1/topics/auth/customizing/#extending-user. Is this perhaps the source of the problem?

Upvotes: 2

Views: 1803

Answers (2)

Vasil Laurynovich
Vasil Laurynovich

Reputation: 464

I also used add_to_class() and created new project in the same enviroment. It need to delete all migrations and *.pyc in subfolders "migrations" in your env. Leave only __init__.py files.

...\Envs\blah-blah-env\Lib\site-packages\django\contrib\...

e.g. path (one of them):

c:\Users\user\Envs\blah-blah-env\Lib\site-packages\django\contrib\auth\migrations\

If you get after (source):

django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency account.0001_initial on database 'default'

delete db or clear migration table, delete migration files in your project. Good luck!

Upvotes: 0

Stuart Dines
Stuart Dines

Reputation: 758

If you are using add_to_class to the Django User model it will detect a change in the external package and apply the migration in the external packages migrations directory (usually in your virtual environment).

It will be referenced in the migration file provided (lucy_web.0184_googlecredentials) at the top if the User model is required for the later migration to be created. The user migration number chosen is the last available at the time of creation to ensure compatibility.

As a bad workaround you could make migrations on the new computer which should create the new user model model migration. Find the file name and alter it temporarily in the migration file lucy_web.0184_googlecredentials

Upvotes: 1

Related Questions