0

I get errors during my initial database migration based on the models defined by django-allauth. I don't have any other models defined, and therefore I have no migration files in my django project.

Django==2.1.5  
django-allauth==0.38.0  
django-pyodbc-azure==2.1.0.0  
Python 3.6.7  
MS SQL Server 16 Build Version 13.0.4474.0 (March 2018)  

This worked fine when I was using SQLite

> python manage.py showmigrations

account  
 [ ] 0001_initial  
 [ ] 0002_email_max_length  
admin  
 [ ] 0001_initial  
 [ ] 0002_logentry_remove_auto_add  
 [ ] 0003_logentry_add_action_flag_choices  
auth  
 [ ] 0001_initial  
 [ ] 0002_alter_permission_name_max_length  
 [ ] 0003_alter_user_email_max_length  
 [ ] 0004_alter_user_username_opts  
 [ ] 0005_alter_user_last_login_null  
 [ ] 0006_require_contenttypes_0002  
 [ ] 0007_alter_validators_add_error_messages  
 [ ] 0008_alter_user_username_max_length  
 [ ] 0009_alter_user_last_name_max_length  
contenttypes  
 [ ] 0001_initial  
 [ ] 0002_remove_content_type_name  
sessions  
 [ ] 0001_initial  
sites  
 [ ] 0001_initial  
 [ ] 0002_alter_domain_unique  
socialaccount  
 [ ] 0001_initial  
 [ ] 0002_token_max_lengths  
 [ ] 0003_extra_data_default_dict  
> python manage.py makemigrations  

No changes detected  

> python manage.py migrate

Operations to perform:  
  Apply all migrations: account, admin, auth, contenttypes, sessions, sites, socialaccount  
Running migrations:  
  Applying account.0001_initial...Traceback (most recent call last):  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute  
    return self.cursor.execute(sql, params)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/sql_server/pyodbc/base.py", line 546, in execute  
    return self.cursor.execute(sql, params)  
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Foreign key 'account_emailaddress_user_id_2c513194_fk_users_customuser_id' references invalid table 'users_customuser'. (1767) (SQLExecDirectW)")  

The above exception was the direct cause of the following exception:  

Traceback (most recent call last):  
  File "manage.py", line 15, in <module>  
    execute_from_command_line(sys.argv)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line  
    utility.execute()  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/core/management/__init__.py", line 375, in execute  
    self.fetch_command(subcommand).run_from_argv(self.argv)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/core/management/base.py", line 316, in run_from_argv  
    self.execute(*args, **cmd_options)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/core/management/base.py", line 353, in execute  
    output = self.handle(*args, **options)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/core/management/base.py", line 83, in wrapped  
    res = handle_func(*args, **kwargs)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 203, in handle  
    fake_initial=fake_initial,  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate  
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards  
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration  
    state = migration.apply(state, schema_editor)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 106, in __exit__  
    self.execute(sql)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/sql_server/pyodbc/schema.py", line 653, in execute  
    cursor.execute(sql, params)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute  
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers  
    return executor(sql, params, many, context)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute  
    return self.cursor.execute(sql, params)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__  
    raise dj_exc_value.with_traceback(traceback) from exc_value  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute  
    return self.cursor.execute(sql, params)  
  File "/home/testuser/envs/venv367/lib/python3.6/site-packages/sql_server/pyodbc/base.py", line 546, in execute  
    return self.cursor.execute(sql, params)  
django.db.utils.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Foreign key 'account_emailaddress_user_id_2c513194_fk_users_customuser_id' references invalid table 'users_customuser'. (1767) (SQLExecDirectW)")  

This is the models.py file in the account app. Please note, this is part of the django-allauth package -- not my code. My code doesn't have any models defined.

from __future__ import unicode_literals

import datetime

from django.core import signing
from django.db import models, transaction
from django.utils import timezone
from django.utils.crypto import get_random_string
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _

from . import app_settings, signals
from .. import app_settings as allauth_app_settings
from .adapter import get_adapter
from .managers import EmailAddressManager, EmailConfirmationManager
from .utils import user_email


@python_2_unicode_compatible
class EmailAddress(models.Model):

    user = models.ForeignKey(allauth_app_settings.USER_MODEL,
                             verbose_name=_('user'),
                             on_delete=models.CASCADE)
    email = models.EmailField(unique=app_settings.UNIQUE_EMAIL,
                              max_length=app_settings.EMAIL_MAX_LENGTH,
                              verbose_name=_('e-mail address'))
    verified = models.BooleanField(verbose_name=_('verified'), default=False)
    primary = models.BooleanField(verbose_name=_('primary'), default=False)

    objects = EmailAddressManager()

    class Meta:
        verbose_name = _("email address")
        verbose_name_plural = _("email addresses")
        if not app_settings.UNIQUE_EMAIL:
            unique_together = [("user", "email")]

    def __str__(self):
        return "%s (%s)" % (self.email, self.user)

    def set_as_primary(self, conditional=False):
        old_primary = EmailAddress.objects.get_primary(self.user)
        if old_primary:
            if conditional:
                return False
            old_primary.primary = False
            old_primary.save()
        self.primary = True
        self.save()
        user_email(self.user, self.email)
        self.user.save()
        return True

    def send_confirmation(self, request=None, signup=False):
        if app_settings.EMAIL_CONFIRMATION_HMAC:
            confirmation = EmailConfirmationHMAC(self)
        else:
            confirmation = EmailConfirmation.create(self)
        confirmation.send(request, signup=signup)
        return confirmation

    def change(self, request, new_email, confirm=True):
        """
        Given a new email address, change self and re-confirm.
        """
        with transaction.atomic():
            user_email(self.user, new_email)
            self.user.save()
            self.email = new_email
            self.verified = False
            self.save()
            if confirm:
                self.send_confirmation(request)


@python_2_unicode_compatible
class EmailConfirmation(models.Model):

    email_address = models.ForeignKey(EmailAddress,
                                      verbose_name=_('e-mail address'),
                                      on_delete=models.CASCADE)
    created = models.DateTimeField(verbose_name=_('created'),
                                   default=timezone.now)
    sent = models.DateTimeField(verbose_name=_('sent'), null=True)
    key = models.CharField(verbose_name=_('key'), max_length=64, unique=True)

    objects = EmailConfirmationManager()

    class Meta:
        verbose_name = _("email confirmation")
        verbose_name_plural = _("email confirmations")

    def __str__(self):
        return "confirmation for %s" % self.email_address

    @classmethod
    def create(cls, email_address):
        key = get_random_string(64).lower()
        return cls._default_manager.create(email_address=email_address,
                                           key=key)

    def key_expired(self):
        expiration_date = self.sent \
            + datetime.timedelta(days=app_settings
                                 .EMAIL_CONFIRMATION_EXPIRE_DAYS)
        return expiration_date <= timezone.now()
    key_expired.boolean = True

    def confirm(self, request):
        if not self.key_expired() and not self.email_address.verified:
            email_address = self.email_address
            get_adapter(request).confirm_email(request, email_address)
            signals.email_confirmed.send(sender=self.__class__,
                                         request=request,
                                         email_address=email_address)
            return email_address

    def send(self, request=None, signup=False):
        get_adapter(request).send_confirmation_mail(request, self, signup)
        self.sent = timezone.now()
        self.save()
        signals.email_confirmation_sent.send(sender=self.__class__,
                                             request=request,
                                             confirmation=self,
                                             signup=signup)


class EmailConfirmationHMAC:

    def __init__(self, email_address):
        self.email_address = email_address

    @property
    def key(self):
        return signing.dumps(
            obj=self.email_address.pk,
            salt=app_settings.SALT)

    @classmethod
    def from_key(cls, key):
        try:
            max_age = (
                60 * 60 * 24 * app_settings.EMAIL_CONFIRMATION_EXPIRE_DAYS)
            pk = signing.loads(
                key,
                max_age=max_age,
                salt=app_settings.SALT)
            ret = EmailConfirmationHMAC(EmailAddress.objects.get(pk=pk))
        except (signing.SignatureExpired,
                signing.BadSignature,
                EmailAddress.DoesNotExist):
            ret = None
        return ret

    def confirm(self, request):
        if not self.email_address.verified:
            email_address = self.email_address
            get_adapter(request).confirm_email(request, email_address)
            signals.email_confirmed.send(sender=self.__class__,
                                         request=request,
                                         email_address=email_address)
            return email_address

    def send(self, request=None, signup=False):
        get_adapter(request).send_confirmation_mail(request, self, signup)
        signals.email_confirmation_sent.send(sender=self.__class__,
                                             request=request,
                                             confirmation=self,
                                             signup=signup)

This is the 0001_initial.py file in the django-allauth package. Not my code.

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
import django.utils.timezone
from django.conf import settings

UNIQUE_EMAIL = getattr(settings, 'ACCOUNT_UNIQUE_EMAIL', True)


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='EmailAddress',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('email', models.EmailField(unique=UNIQUE_EMAIL, max_length=75, verbose_name='e-mail address')),
                ('verified', models.BooleanField(default=False, verbose_name='verified')),
                ('primary', models.BooleanField(default=False, verbose_name='primary')),
                ('user', models.ForeignKey(verbose_name='user', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
            ],
            options={
                'verbose_name': 'email address',
                'verbose_name_plural': 'email addresses',
            },
            bases=(models.Model,),
        ),
        migrations.CreateModel(
            name='EmailConfirmation',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('created', models.DateTimeField(default=django.utils.timezone.now, verbose_name='created')),
                ('sent', models.DateTimeField(null=True, verbose_name='sent')),
                ('key', models.CharField(unique=True, max_length=64, verbose_name='key')),
                ('email_address', models.ForeignKey(verbose_name='e-mail address', to='account.EmailAddress', on_delete=models.CASCADE)),
            ],
            options={
                'verbose_name': 'email confirmation',
                'verbose_name_plural': 'email confirmations',
            },
            bases=(models.Model,),
        ),
    ]

    if not UNIQUE_EMAIL:
        operations += [
            migrations.AlterUniqueTogether(
                name='emailaddress',
                unique_together=set([('user', 'email')]),
            ),
        ]

I expect a clean migration, with tables created. Actually got a few tables created before the error.

Jonathan
  • 491
  • 5
  • 19
  • 1
    show us your `models.py` And `0001_initial` of accounts app. – Ahtisham Feb 05 '19 at 06:18
  • Take a look at this post: https://stackoverflow.com/questions/49137052/django-programmingerror-42s02-microsoftodbc-driver-13-for-sql-serversql-s – Ahtisham Feb 05 '19 at 06:23
  • Added models.py and 0001_initial.py -- please note, these are from the django-allauth package -- not my code. My code doesn't have any models defined. I'm trying to run a clean install of django-allauth. I also followed the SO post above, and tried to delete all migrations, and fake migrations (but this isn't really pertinent because ther are no migrations in my code since I have no user-defined models). Thanks for the help so far! – Jonathan Feb 05 '19 at 14:54

2 Answers2

2

All error due to all auth not match with upgrade django version you just need to upgrade all auth to satisfy error.

Try this:

pip install --upgrade django-allauth
fcdt
  • 2,371
  • 5
  • 14
  • 26
Prince Raj
  • 52
  • 7
1

The error message:

pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Foreign key 'account_emailaddress_user_id_2c513194_fk_users_customuser_id' references invalid table 'users_customuser'. (1767) (SQLExecDirectW)")

tells you that the migration is trying to find a custom user table by the name of users_customuser. That tells me that somewhere in your settings file you probably have:

AUTH_USER_MODEL = 'users.customuser'

The Django docs highly recommend creating a custom user model before starting a project, however, you don't have to. If you have the above somewhere in your settings, then you would have to create the CustomUser model in the users app. The easiest way to do that is to use from django.contrib.auth.models import AbstractUser (not AbstractBaseUser) as noted in the above Django instructions. Alternatively, you could also just remove the AUTH_USER_MODEL = 'users.customuser' from your code and stick with Django's default user model. If you use a custom user model, then create the migrations for that app first - assuming the app name is users, do:

python manage.py makemigrations users

If you remove the AUTH_USER_MODEL = ... from settings, then you should be able to just do python manage.py migrate.

Dan Swain
  • 2,910
  • 1
  • 16
  • 36
  • yep . . . that worked. My mistake is that I thought "python manage.py makemigrations" created migrations for all apps in the Django project. I appreciate the help. – Jonathan Feb 05 '19 at 16:48
  • 1
    Just one other thought: "python manage.py makemigrations" DOES create migrations for all apps in the project which already have a migrations folder, but you have to specify the app name in order to create the first set of migrations for an app. – Dan Swain Feb 05 '19 at 16:51