前提・実現したいこと
既存プロジェクトにDjangoのカスタムユーザを作成したいと考えています。
以下の記事にしたがって実装することにしました。
Djangoではカスタムユーザを作るべきらしい
ソースコードはほぼコピペで、マイグレーションを実施後、管理者アカウント作成しようとした際に、Userテーブルが存在しないというエラーになってしまいます。
マイグレーションファイルからUserテーブルが生成されて欲しいです。
既存プロジェクトのDBはMySQLを使っています。
発生している問題・エラーメッセージ
$ python manage.py createsuperuser Username: admin ---中略--- django.db.utils.ProgrammingError: (1146, "Table 'hoge.hoge_project_user' doesn't exist")
該当のソースコード
マイグレーションファイルは以下の通りです。
Python
1 operations = [ 2 migrations.CreateModel( 3 name='User', 4 fields=[ 5 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 6 ('password', models.CharField(max_length=128, verbose_name='password')), 7 ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 8 ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 9 ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), 10 ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), 11 ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), 12 ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), 13 ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 14 ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), 15 ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 16 ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), 17 ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), 18 ], 19 options={ 20 'verbose_name': 'user', 21 'verbose_name_plural': 'users', 22 }, 23 managers=[ 24 ('objects', hoge_project.models.UserManager()), 25 ], 26 ), 27 ]
ユーザモデル関連は記事のコピペですが、以下の通りです。
Python
1class UserManager(BaseUserManager): 2 use_in_migrations = True 3 4 def _create_user(self, username, email, password, **extra_fields): 5 """ 6 Create and save a user with the given username, email, and password. 7 """ 8 if not username: 9 raise ValueError('The given username must be set') 10 email = self.normalize_email(email) 11 username = self.model.normalize_username(username) 12 user = self.model(username=username, email=email, **extra_fields) 13 user.set_password(password) 14 user.save(using=self._db) 15 return user 16 17 def create_user(self, username, email=None, password=None, **extra_fields): 18 extra_fields.setdefault('is_staff', False) 19 extra_fields.setdefault('is_superuser', False) 20 return self._create_user(username, email, password, **extra_fields) 21 22 def create_superuser(self, username, email, password, **extra_fields): 23 extra_fields.setdefault('is_staff', True) 24 extra_fields.setdefault('is_superuser', True) 25 26 if extra_fields.get('is_staff') is not True: 27 raise ValueError('Superuser must have is_staff=True.') 28 if extra_fields.get('is_superuser') is not True: 29 raise ValueError('Superuser must have is_superuser=True.') 30 31 return self._create_user(username, email, password, **extra_fields) 32 33 34class User(AbstractBaseUser, PermissionsMixin): 35 """ 36 An abstract base class implementing a fully featured User model with 37 admin-compliant permissions. 38 Username and password are required. Other fields are optional. 39 """ 40 username_validator = UnicodeUsernameValidator() 41 42 username = models.CharField( 43 _('username'), 44 max_length=150, 45 unique=True, 46 help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'), 47 validators=[username_validator], 48 error_messages={ 49 'unique': _("A user with that username already exists."), 50 }, 51 ) 52 first_name = models.CharField(_('first name'), max_length=30, blank=True) 53 last_name = models.CharField(_('last name'), max_length=150, blank=True) 54 email = models.EmailField(_('email address'), blank=True) 55 is_staff = models.BooleanField( 56 _('staff status'), 57 default=False, 58 help_text=_('Designates whether the user can log into this admin site.'), 59 ) 60 is_active = models.BooleanField( 61 _('active'), 62 default=True, 63 help_text=_( 64 'Designates whether this user should be treated as active. ' 65 'Unselect this instead of deleting accounts.' 66 ), 67 ) 68 date_joined = models.DateTimeField(_('date joined'), default=timezone.now) 69 70 objects = UserManager() 71 72 EMAIL_FIELD = 'email' 73 USERNAME_FIELD = 'username' 74 REQUIRED_FIELDS = ['email'] 75 76 class Meta: 77 verbose_name = _('user') 78 verbose_name_plural = _('users') 79 # abstract = True # ここを削除しないといけないことを忘れない!!!!!!!!!! 80 81 def clean(self): 82 super().clean() 83 self.email = self.__class__.objects.normalize_email(self.email) 84 85 def get_full_name(self): 86 """ 87 Return the first_name plus the last_name, with a space in between. 88 """ 89 full_name = '%s %s' % (self.first_name, self.last_name) 90 return full_name.strip() 91 92 def get_short_name(self): 93 """Return the short name for the user.""" 94 return self.first_name 95 96 def email_user(self, subject, message, from_email=None, **kwargs): 97 """Send an email to this user.""" 98 send_mail(subject, message, from_email, [self.email], **kwargs) 99
試したこと
新規プロジェクトを作成して、丸々記事の通り実装したところ、問題なく実装できました。
マイグレーションファイルを比較しましたが、違いは分かりませんでした。
補足情報(FW/ツールのバージョンなど)
mysql: 8.0.17
python: 3.7.3
django: 2.2.3
あなたの回答
tips
プレビュー