Django 扩展 AbstractUser 没有这样的 table 错误
Django extend AbstractUser no such table error
我正在尝试在 python 3.8.0 上扩展 django 3.0.1 (drf==3.10.3) AbstractUser。
尝试在管理页面和 JWT 上登录时出现 no such table <appName>_user
错误。
我的项目目录结构:
root
-|app
--|<projectName>
---|<appName>
---|statics
---|__init__.py
---|settings.py
---|urls.py
---|wsgi.py
---|asgi.py
--|manage.py
--|.env
--|db.sql
我的app/projectName/appName/migrations
和app/projectName/appName/tests
上有__init__.py
。
这里是 settings.py
文件的相关部分:
BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(
os.path.abspath(__file__))), '<projectName>/')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'drf_yasg', # openapi
# local
'<projectName>.<appName>',
]
if DEBUG:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': env.str('DATABASE_NAME', 'db.sqlite3'),
'HOST': env.str('DATABASE_HOST', os.path.join(BASE_DIR, 'db.sqlite3')),
'PORT': env.int('DATABASE_PORT', '5000')
},
'test': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': env.str('DATABASE_NAME', 'testing.sqlite3'),
'HOST': env.str('DATABASE_HOST', os.path.join(BASE_DIR, 'testing.sqlite3')),
'PORT': env.int('DATABASE_PORT', '5000')
}
}
else:
DATABASES = {
'default': env.db(),
}
AUTH_USER_MODEL = '<appName>.User'
我的相关部分appName/models.py
:
class User(AbstractUser):
role = models.CharField(
max_length=15,
choices=[(tag, tag.value)
for tag in UserRolesChoise] # Choices is a list of Tuple
)
is_vendor = models.BooleanField(
_('vendor status'),
default=False,
help_text=_(
'Designates whether the user is a vendor.'),
)
is_customer = models.BooleanField(
_('customer status'),
default=True,
help_text=_(
'Designates whether the user is a customer.'),
)
def __str__(self):
return self.username
我的相关部分 appName/serializers.py
:
from rest_framework import serializers
from django.contrib.auth import get_user_model
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'email', 'last_login', 'first_name', 'last_name',
'get_full_name', 'is_staff', 'is_active', 'date_joined', 'is_vendor', 'is_customer')
我的相关部分appName/urls.py
:
from django.urls import path, re_path, include
from django.contrib import admin
from rest_framework import routers
from .<appName> import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls))
]
我的相关部分appName/views.py
:
from rest_framework import viewsets
from .serializers import UserSerializer
from .premissions import IsOwnerOrAdmin
from django.contrib.auth import get_user_model
User = get_user_model()
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [IsOwnerOrAdmin,]
和我的相关部分 appName/apps.py
:
from django.apps import AppConfig
class <AppName>Config(AppConfig):
name = '<appName>'
这是一个正在开发的系统,所以我尝试通过 运行 在我的应用程序文件夹中删除所有迁移和数据库:
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc" -delete
rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
奇怪的事情:
当我 运行 python manage.py dbshell
并输入 .tables
时,我的 <appname>_user
正在显示。
我位于 <appName>/tests/test_*.py
的一些测试通过得很好:
from rest_framework import status
from rest_framework.test import APITestCase
from django.contrib.auth import get_user_model
User = get_user_model()
class UserModelTestCase(APITestCase):
""" Test module for User model """
def setUp(self):
super(UserModelTestCase, self).setUp()
self.given_user_exists(first_name='Test', last_name='Customer', email="customer@gmail.com", password="7789",
username="Test Customer", role='Customer')
self.given_user_exists(
first_name='Test', last_name='Vendor', email="vendor@gmail.com", password="7789",
username="Test Vendor",
role='Vendor', is_vendor=True, is_customer=False)
self.given_user_exists(
first_name='Test', last_name='Staff', email="stff@gmail.com", password="7789",
username="Test Staff",
role='Admin', is_customer=False, is_staff=True)
self.user_customer=User.objects.get(username='Test Customer')
self.user_vendor=User.objects.get(username='Test Vendor')
self.user_staff=User.objects.get(username='Test Staff')
def tearDown(self):
super(UserModelTestCase, self).tearDown()
def test_all_users_hidden_for_anonymous_users(self):
all_users = self.client.get('/api/v1/users/')
self.assertEqual(all_users.status_code,status.HTTP_401_UNAUTHORIZED)
我编写的所有代码中都没有<>。
这让我认为这是一个数据库问题,但我不明白这个问题。
您还需要实施自己的 BaseUserManager
。在您的 models.py
添加以下代码
from django.contrib.auth.base_user import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
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, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_staff', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
return self._create_user(email, password, **extra_fields)
希望对您有所帮助!
请检查 User 模型在 Meta class 中是否有 abstract = True
。删除此行(如果存在)。
如果它具有 abstract = True 属性,则此模型将不会用于创建任何数据库 table。看起来像你的情况。
我不得不继续这个项目,所以我做了我能想到的不太聪明的事情 - 运行 远离这个问题,我现在确定这是一个设置问题。
如果它对某人有帮助,这就是我所做的:
- 我为项目创建了一个新的根。
- 在此文件夹中,我 运行
python manage.py start app <appName>
用于创建我的应用程序。这是我当前的文件:
root
-|<projectName>
--|<projectName>
---|__init__.py
---|settings.py
---|urls.py
---|wsgi.py
---|asgi.py
--|<appName>
---|apps.py
---|views.py
---|_init__.py
---|serializers.py
---|etc...
--|statics
--|manage.py
--|.env
--|db.sql
- 删除了 db.sql 个文件、迁移和
__pycache__
个文件夹。
- 从原始文件夹中复制了相关代码片段。
- 根据新项目更改了设置和导入。
TL;DR
创建新项目结构、删除迁移、__pycache__
文件夹和数据库文件后,一切正常。
我正在尝试在 python 3.8.0 上扩展 django 3.0.1 (drf==3.10.3) AbstractUser。
尝试在管理页面和 JWT 上登录时出现 no such table <appName>_user
错误。
我的项目目录结构:
root
-|app
--|<projectName>
---|<appName>
---|statics
---|__init__.py
---|settings.py
---|urls.py
---|wsgi.py
---|asgi.py
--|manage.py
--|.env
--|db.sql
我的app/projectName/appName/migrations
和app/projectName/appName/tests
上有__init__.py
。
这里是 settings.py
文件的相关部分:
BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(
os.path.abspath(__file__))), '<projectName>/')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'drf_yasg', # openapi
# local
'<projectName>.<appName>',
]
if DEBUG:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': env.str('DATABASE_NAME', 'db.sqlite3'),
'HOST': env.str('DATABASE_HOST', os.path.join(BASE_DIR, 'db.sqlite3')),
'PORT': env.int('DATABASE_PORT', '5000')
},
'test': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': env.str('DATABASE_NAME', 'testing.sqlite3'),
'HOST': env.str('DATABASE_HOST', os.path.join(BASE_DIR, 'testing.sqlite3')),
'PORT': env.int('DATABASE_PORT', '5000')
}
}
else:
DATABASES = {
'default': env.db(),
}
AUTH_USER_MODEL = '<appName>.User'
我的相关部分appName/models.py
:
class User(AbstractUser):
role = models.CharField(
max_length=15,
choices=[(tag, tag.value)
for tag in UserRolesChoise] # Choices is a list of Tuple
)
is_vendor = models.BooleanField(
_('vendor status'),
default=False,
help_text=_(
'Designates whether the user is a vendor.'),
)
is_customer = models.BooleanField(
_('customer status'),
default=True,
help_text=_(
'Designates whether the user is a customer.'),
)
def __str__(self):
return self.username
我的相关部分 appName/serializers.py
:
from rest_framework import serializers
from django.contrib.auth import get_user_model
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'email', 'last_login', 'first_name', 'last_name',
'get_full_name', 'is_staff', 'is_active', 'date_joined', 'is_vendor', 'is_customer')
我的相关部分appName/urls.py
:
from django.urls import path, re_path, include
from django.contrib import admin
from rest_framework import routers
from .<appName> import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls))
]
我的相关部分appName/views.py
:
from rest_framework import viewsets
from .serializers import UserSerializer
from .premissions import IsOwnerOrAdmin
from django.contrib.auth import get_user_model
User = get_user_model()
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [IsOwnerOrAdmin,]
和我的相关部分 appName/apps.py
:
from django.apps import AppConfig
class <AppName>Config(AppConfig):
name = '<appName>'
这是一个正在开发的系统,所以我尝试通过 运行 在我的应用程序文件夹中删除所有迁移和数据库:
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc" -delete
rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
奇怪的事情:
当我 运行 python manage.py dbshell
并输入 .tables
时,我的 <appname>_user
正在显示。
我位于 <appName>/tests/test_*.py
的一些测试通过得很好:
from rest_framework import status
from rest_framework.test import APITestCase
from django.contrib.auth import get_user_model
User = get_user_model()
class UserModelTestCase(APITestCase):
""" Test module for User model """
def setUp(self):
super(UserModelTestCase, self).setUp()
self.given_user_exists(first_name='Test', last_name='Customer', email="customer@gmail.com", password="7789",
username="Test Customer", role='Customer')
self.given_user_exists(
first_name='Test', last_name='Vendor', email="vendor@gmail.com", password="7789",
username="Test Vendor",
role='Vendor', is_vendor=True, is_customer=False)
self.given_user_exists(
first_name='Test', last_name='Staff', email="stff@gmail.com", password="7789",
username="Test Staff",
role='Admin', is_customer=False, is_staff=True)
self.user_customer=User.objects.get(username='Test Customer')
self.user_vendor=User.objects.get(username='Test Vendor')
self.user_staff=User.objects.get(username='Test Staff')
def tearDown(self):
super(UserModelTestCase, self).tearDown()
def test_all_users_hidden_for_anonymous_users(self):
all_users = self.client.get('/api/v1/users/')
self.assertEqual(all_users.status_code,status.HTTP_401_UNAUTHORIZED)
我编写的所有代码中都没有<>。
这让我认为这是一个数据库问题,但我不明白这个问题。
您还需要实施自己的 BaseUserManager
。在您的 models.py
from django.contrib.auth.base_user import BaseUserManager
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, password, **extra_fields):
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, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_staff', False)
return self._create_user(email, password, **extra_fields)
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_staff', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
return self._create_user(email, password, **extra_fields)
希望对您有所帮助!
请检查 User 模型在 Meta class 中是否有 abstract = True
。删除此行(如果存在)。
如果它具有 abstract = True 属性,则此模型将不会用于创建任何数据库 table。看起来像你的情况。
我不得不继续这个项目,所以我做了我能想到的不太聪明的事情 - 运行 远离这个问题,我现在确定这是一个设置问题。
如果它对某人有帮助,这就是我所做的:
- 我为项目创建了一个新的根。
- 在此文件夹中,我 运行
python manage.py start app <appName>
用于创建我的应用程序。这是我当前的文件:
root
-|<projectName>
--|<projectName>
---|__init__.py
---|settings.py
---|urls.py
---|wsgi.py
---|asgi.py
--|<appName>
---|apps.py
---|views.py
---|_init__.py
---|serializers.py
---|etc...
--|statics
--|manage.py
--|.env
--|db.sql
- 删除了 db.sql 个文件、迁移和
__pycache__
个文件夹。 - 从原始文件夹中复制了相关代码片段。
- 根据新项目更改了设置和导入。
TL;DR
创建新项目结构、删除迁移、__pycache__
文件夹和数据库文件后,一切正常。