Django自定义用户模型问题

时间:2018-09-27 09:45:50

标签: python django django-models django-rest-framework django-custom-user

我正在尝试自定义用户模型(名称:UserProfile),但是在进行迁移时出现错误:

AttributeError: Manager isn't available; 'auth.User' has been swapped for 'accounts.UserProfile'

所以我遵循(Manager isn't available; User has been swapped for 'pet.Person')的建议,并进行了一些更改。我放

from django.contrib.auth import get_user_model
User = get_user_model()

在自定义用户模型导入的每个文件中(设置,序列化程序,模型,表单,管理),但是这次我又收到了另一条错误消息:

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

如何解决此问题?

以下是文件:

settings.py

> import os import datetime from django.conf import settings
> 
> 
> # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR =
> os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
> 
> 
> # Quick-start development settings - unsuitable for production
> # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
> 
> # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'ruho^096p16m=vg!sn(&o46-qwe#y(zf^bee&!wujo-4h@%hgl'
> 
> # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True
> 
> ALLOWED_HOSTS = ['*']
> 
> 
> # Application definition INSTALLED_APPS = [
>     'rest_framework', # Django rest framework 套件
>     'rest_framework.authtoken',
>     'grappelli', # grappelli admin 版面套件
>     'django.contrib.admin',
>     'django.contrib.auth',
>     'django.contrib.contenttypes',
>     'django.contrib.sessions',
>     'django.contrib.messages',
>     'django.contrib.staticfiles',
>     'django.contrib.sites',
>     'rest_auth',
>     'rest_auth.registration',
>     'debug_toolbar', # django debug 工具列
>     'django_extensions', # django 擴展套件,提供一些cli指令
>     'import_export', # 可從 admin 匯出資料 (目前因版本關係,所以無法使用)
>     'django_filters', # 優化從model query 資料效能
>     'allauth', # django allauth 套件
>     'allauth.account', # django allauth 套件
>     'allauth.socialaccount',  # django allauth 套件
>     'allauth.socialaccount.providers.facebook',  # django allauth 套件,設定使用FB登入用
>     # 'rest_framework_docs', # 可輸出API文件 (目前因版本關係,所以無法使用)
>     'books', # 書籍APP
>     'accounts',# 使用者帳號APP ]
> 
> from django.contrib.auth import get_user_model 
  User = get_user_model()
> 
> AUTH_USER_MODEL = 'accounts.UserProfile'
> 
> MIDDLEWARE = [
>     'django.middleware.security.SecurityMiddleware',
>     'django.contrib.sessions.middleware.SessionMiddleware',
>     'django.middleware.common.CommonMiddleware',
>     'django.middleware.csrf.CsrfViewMiddleware',
>     'django.contrib.auth.middleware.AuthenticationMiddleware',
>     'django.contrib.messages.middleware.MessageMiddleware',
>     'django.middleware.clickjacking.XFrameOptionsMiddleware',
>     'debug_toolbar.middleware.DebugToolbarMiddleware', ]
> 
> INTERNAL_IPS = ('127.0.0.1',)
> 
> # 配置django_rest_framework REST_FRAMEWORK = {
>     # Use Django's standard `django.contrib.auth` permissions,
>     # or allow read-only access for unauthenticated users.
>     'DEFAULT_AUTHENTICATION_CLASSES': (
>         'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
>         'rest_framework.authentication.SessionAuthentication',
>         'rest_framework.authentication.BasicAuthentication',
>     ),
>     'DEFAULT_PERMISSION_CLASSES': [
>         'rest_framework.permissions.IsAuthenticated',
>     ] }
> 
> # 配置JQuery和SHOW_TOOLBAR_​​CALLBACK DEBUG_TOOLBAR_CONFIG = {
>     'JQUERY_URL': 'https://ajax.googleapis.com/ajax/libs/dojo/1.13.0/dojo/dojo.js',
>     'SHOW_TOOLBAR_​​CALLBACK': lambda request: DEBUG, } 
 ....

model.py

from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from books.models import Bookinfo
from datetime import datetime, timedelta
import jwt

from django.contrib.auth import get_user_model
User = get_user_model()


# 建立usermanager定義使用者和高級使用者instance作為數據查詢的管理器
class UserManager(BaseUserManager):

    # 建立一般使用者
    def create_user(self, username, email, password=None):

        # 判斷使用者是否有輸入使用者名稱和email
        if username is None:
            raise TypeError('請填入使用者名稱')
        if email is None:
            raise TypeError('請填入Email')

        user = self.model(
            username=username,
            email=self.normalize_email(email)
        )
        user.set_password(password)
        user.save()

        return user

    # 建立高級使用者
    def create_superuser(self, username, email, password):

        if password is None:
            raise TypeError('Superusers must have a password')

        # 直接使用建立一般使用者方法
        user = self.create_user(username, email, password)
        user.is_superuser = True
        user.is_staff = True
        user.save()

        return user

# 定義使用者資料表
class UserProfile(AbstractBaseUser, PermissionsMixin):

    class Meta:
        db_table = 'userprofile'

    # 定義使用者需填入資料
    username = models.CharField(max_length=255, db_index=True, unique=True, verbose_name='用戶名')
    user_image = models.ImageField(upload_to='img', verbose_name='用戶圖片')
    email = models.EmailField(db_index=True, unique=True, verbose_name='電子郵件')
    birthday = models.DateField(verbose_name='生日')
    GENDER_CHOICES = (
        ('Male', '男'), 
        ('Female', '女')
    )
    gender = models.CharField(
        max_length=5, choices=GENDER_CHOICES, verbose_name='性別')
    location = models.CharField(max_length=255, blank=True, verbose_name='地區')
    about = models.TextField(blank=True, verbose_name='關於我')

    # 確認使用者是否還有再使用平台
    is_active = models.BooleanField(default=True)
    # 確認使用者是否為管理者
    is_staff = models.BooleanField(default=False)

    # 創建時間 
    create_at = models.DateTimeField(auto_now_add=True)
    # 更新資料時間
    update_at = models.DateTimeField(auto_now=True)

    # 外鍵:將評論和書櫃關聯起來
    com = models.OneToOneField(
         'Comments', null=True, blank=True, on_delete=models.CASCADE, verbose_name='評論ID')
    bookshelf = models.OneToOneField(
         'bookshelf', null=True, blank=True, on_delete=models.CASCADE, verbose_name='書櫃ID')

    # The `USERNAME_FIELD` property tells us which field we will use to log in.
    # In this case we want it to be the email field.
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    # Tells Django that the UserManager class defined above should manage
    # objects of this type.
    objects = UserManager()

    def __str__(self):
        """
        Returns a string representation of this `User`.

        This string is used when a `User` is printed in the console.
        """
        return self.email

    @property
    def token(self):
        """
        Allows us to get a user's token by calling `user.token` instead of
        `user.generate_jwt_token().

        The `@property` decorator above makes this possible. `token` is called
        a "dynamic property".
        """
        return self._generate_jwt_token()

    def get_full_name(self):
        """
        This method is required by Django for things like handling emails.
        Typically this would be the user's first and last name. Since we do
        not store the user's real name, we return their username instead.
        """
        return self.username

    def get_short_name(self):
        """
        This method is required by Django for things like handling emails.
        Typically, this would be the user's first name. Since we do not store
        the user's real name, we return their username instead.
        """
        return self.username

    def _generate_jwt_token(self):
        """
        Generates a JSON Web Token that stores this user's ID and has an expiry
        date set to 60 days into the future.
        """
        dt = datetime.now() + timedelta(days=60)

        token = jwt.encode({
            'id': self.pk,
            'exp': int(dt.strftime('%s'))
        }, settings.SECRET_KEY, algorithm='HS256')

        return token.decode('utf-8') ....

form.py

from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import UserProfile

from django.contrib.auth import get_user_model
User = get_user_model()

class UserProfileForm(UserCreationForm):
    class Meta:
        model = UserProfile
        fields = (
            'username', 'user_image', 'email', 'gender',
            'birthday', 'location', 'about' 
        )


class UserProfileChangeForm(UserChangeForm):
    class Meta:
        model = UserProfile
        fields = UserChangeForm.Meta.fields

admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Comments, Bookshelf, UserProfile
from import_export.admin import ImportExportModelAdmin
from .forms import UserCreationForm, UserChangeForm

from django.contrib.auth import get_user_model
User = get_user_model()

class UserProfileAdmin(UserAdmin):
    add_form = UserCreationForm
    form = UserChangeForm
    model = UserProfile
    list_display = ('_id', 'user_name', 'e-mail', 'gender',
                    'birthday', 'location', 'created_at')
    search_fields = ['user_name', 'gender']

class CommentsAdmin(ImportExportModelAdmin):
    list_display = ('_id', 'rating', 'read_status', 'created_time')
    search_fields = ['rating']

class BookshelfAdmin(ImportExportModelAdmin):
    list_display = ('_id', 'created_time')
    # search_fields = ['gender']


admin.site.register(UserProfile, UserProfileAdmin)
admin.site.register(Comments, CommentsAdmin)
admin.site.register(Bookshelf, BookshelfAdmin)

版本:Django 2.1.1,python 3.6.3

1 个答案:

答案 0 :(得分:0)

自定义User = get_user_model()模型时,不需要使用

User。我认为您应该继承AbstractUser模型。 AbstractUser模型提供了auth.User(包括管理人员,权限,验证)所有用户模型。