質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.79%

Djangoでカスタムユーザーのマイグレーションが実行できない、'app_name.User' that has not been installed

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 735
退会済みユーザー

退会済みユーザー

前提・実現したいこと

Djangoにて、emailで認証する形式のコミュニケーションツールを作成しようとしています。
Djangoの開発経験は初めてで、ドキュメントを読みながら進めているレベルです(このようなサービスで質問することも初めてのため、粗相がありましたらご助言いただけると嬉しく思います)。

email認証のカスタムユーザーを作りたく、ドキュメントのチュートリアルこちらの記事を参考に進めておりましたが、
python manage.py migrateの実行で詰まってしまいました。

stack overflowやteratailでも似たような症状を見かけましたが、そのアンサーを真似しても解決できなかったため、自分で気づいていない問題点や解決策をご教授いただきたいです。

発生している問題・エラーメッセージ

python manage.py migrateの実行で、以下のようなエラーが起きました。

LookupError: App 'floattle' doesn't have a 'User' model. と django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'floattle.User' that has not been installed に注目しています。

Traceback (most recent call last):
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/apps/config.py", line 178, in get_model
    return self.models[model_name.lower()]
KeyError: 'user'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/contrib/auth/__init__.py", line 156, in get_user_model
    return django_apps.get_model(settings.AUTH_USER_MODEL, require_ready=False)
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/apps/registry.py", line 210, in get_model
    return app_config.get_model(model_name, require_ready=require_ready)
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/apps/config.py", line 181, in get_model
    "App '%s' doesn't have a '%s' model." % (self.label, model_name))
LookupError: App 'floattle' doesn't have a 'User' model.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/core/management/__init__.py", line 377, in execute
    django.setup()
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/apps/registry.py", line 122, in populate
    app_config.ready()
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/contrib/admin/apps.py", line 24, in ready
    self.module.autodiscover()
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/contrib/admin/__init__.py", line 26, in autodiscover
    autodiscover_modules('admin', register_to=site)
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/utils/module_loading.py", line 47, in autodiscover_modules
    import_module('%s.%s' % (app_config.name, module_to_search))
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/contrib/auth/admin.py", line 6, in <module>
    from django.contrib.auth.forms import (
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/contrib/auth/forms.py", line 20, in <module>
    UserModel = get_user_model()
  File "/Users/nagamiya/.pyenv/versions/3.6.5/lib/python3.6/site-packages/django/contrib/auth/__init__.py", line 161, in get_user_model
    "AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'floattle.User' that has not been installed

ファイルの構造

floattleがアプリ名称です。スクリーンショットで失礼いたします。
ファイル構造

該当のソースコード

settings.pyの抜粋です。AUTH_USER_MODEL〜の後にはMIDDLEWAREやROOT_URLCONF、TEMPLATESなどが記述してあります。

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'qg27x8s5ju-61*6jdp$$@s3@9=7rv63^f0x9uvl+ukl^fkt+_e'

DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'floattle.apps.FloattleConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

# カスタムユーザクラスを使用
AUTH_USER_MODEL = 'floattle.User'

models.pyです。

from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils import timezone
from django.contrib.auth.models import PermissionsMixin, UserManager
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import gettext_lazy as _


# usernameではなくemailで認証をする
class UserManager(UserManager):
    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """
        Create and save a user with the given username, email, and password.
        """
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email=None, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    name_validator = UnicodeUsernameValidator()
    name = models.CharField(
        _('name'),
        max_length=30,
        help_text=_('Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.'
                    ),
        validators=[name_validator]
    )
    email = models.EmailField(_('email address'), unique=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_(
            'Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'),
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    last_login = models.DateTimeField(
        _('date last login'), default=timezone.now())

    objects = UserManager()

    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        abstract = True
    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def email_user(self, subject, message, from_email=None, **kwargs):
        ''' Send an email to this user. '''
        send_mail(subject, message, from_email, [self.email], **kwargs)

    @property
    def username(self):
        ''' username属性のgetter '''
        return self.email


class Post(models.Model):
    user = models.ForeignKey('User', on_delete=models.CASCADE)
    text = models.TextField(max_length=400)
    shed_count = models.IntegerField()
    is_active = models.BooleanField(default=True)
    keep = models.ManyToManyField(User)
    date_published = models.DateTimeField(blank=True, null=True)
    date_deleted = models.DateTimeField(blank=True, null=True)

    ''' 文字数によって紙のデザインが変わるようにそのうちしたいので定義しておいた '''
    def length(self):
        return len(self.text)

試したこと

  • settings.pyの編集
    INSTALLED_APPSに追記する部分を変えてみました。
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'floattle', #ここです
]
  • apps.pyの確認
from django.apps import AppConfig

class FloattleConfig(AppConfig):
    name = 'floattle'
  • admin.pyの編集
    上記の参考サイトを真似しつつ、必要な部分を変えて書いていました。このファイルが原因...?と思い、書いた状態とデフォルトの状態で試してみましたが変化がありませんでした。

  • マイグレーションとDBの削除
    マイグレーションが実行すらできていない状態のため不要かと思いましたが、念のために試してみました。

  • プロジェクトごと作り直し

補足情報(FW/ツールのバージョンなど)

Django 3.0.8
Python 3.6.5
MySQL
仮想環境は今回使っておりません...(これは何か関係しているのでしょうか)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • ForestSeo

    2020/07/27 20:08 編集

    forms.pyはどうですか?

    https://stackoverrun.com/ja/q/9283727がかなり似ている気がします。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2020/07/27 20:17

    コメントいただき有難うございます。
    forms.pyについてはまだ作成していないのですが、マイグレーション実行時点でforms.pyも参照されているのでしょうか...(Djangoの仕組みを理解できておらず、初歩的な疑問で申し訳ございません)

    ご紹介いただいたページを見つつ、forms.pyを生成してみようと思います。

    キャンセル

  • ForestSeo

    2020/07/28 04:25

    forms.py書いてないなら大丈夫です。そのままで。
    どこのファイルでエラーが起きているのかなと思いまして。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2020/07/28 10:54

    そういうことでしたか、ご教授いただきありがとうございます。
    引き続きもう少し調べてみます...!

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る