![](/img/trans.png)
[英]Can't login to Django admin panel after successfully creating superuser using Django custom user model
[英]FOREIGN KEY constraint failed in django admin panel when creating/editing/deleting a user. (Using custom user model.)
所以我使用自定義用戶模型
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class UserManager(BaseUserManager):
def create_user(self, email, full_name, address, number, password=None):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
if not full_name:
raise ValueError('Users must have an email address')
if not address:
raise ValueError('Users must have an email address')
if not number:
raise ValueError('Users must have an email address')
if not password:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email.lower()),
full_name=full_name,
address = address,
number=number,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_staffuser(self, email, full_name, address, number, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
full_name,
address,
numbe,
password = password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, full_name, address, number, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(
email,
full_name,
address,
number,
password = password,
)
user.staff = True
user.admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, blank = False, null = False)
address = models.CharField(max_length=255, blank = False, null = False)
number = models.CharField(max_length=255, blank = False, null = False)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
# notice the absence of a "Password field", that's built in.
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name', 'address', 'number'] # Email & Password are required by default.
objects = UserManager()
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
return self.staff
@property
def is_admin(self):
"Is the user a admin member?"
return self.admin
@property
def is_active(self):
"Is the user active?"
return self.active
這是我的應用程序 admin.py
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserAdminChangeForm, UserAdminCreationForm
from .models import User
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'admin')
list_filter = ('admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('full_name', 'address', 'number')}),
('Permissions', {'fields': ('admin', 'active', 'staff')}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'full_name', 'address', 'number', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
admin.site.unregister(Group)
最后是forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class UserAdminCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email', 'full_name', 'address', 'number')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'full_name', 'address', 'number', 'password', 'active', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
因此,當我通過帶有 manage.py 的控制台創建超級用戶時,它工作得很好,但是當我決定在 gui 管理面板中編輯、刪除或創建另一個用戶時,我得到一個“外鍵約束失敗”。 我不明白,有人能指出我正確的方向嗎?
我想我已經找到了解決方案。 當您將默認 AUTH_USER_MODEL 遷移到項目中間的自定義模型時,該問題很可能是由循環依賴問題引起的。
來自 Django 文檔
例如,在創建數據庫表之后更改 AUTH_USER_MODEL 會困難得多,因為它會影響外鍵和多對多關系。
此更改無法自動完成,需要手動修復架構、從舊用戶表中移動數據,並可能手動重新應用某些遷移。 有關步驟的概述,請參閱 #25313。
由於Django對可交換模型的動態依賴特性的限制,AUTH_USER_MODEL引用的模型必須在其app的第一次遷移中創建(通常稱為0001_initial); 否則,您將遇到依賴性問題。
此外,在運行遷移時可能會遇到 CircularDependencyError,因為由於動態依賴,Django 將無法自動中斷依賴循環。 如果您看到此錯誤,您應該通過將用戶模型依賴的模型移動到第二次遷移來打破循環。 (如果您想了解通常是如何完成的,您可以嘗試制作兩個彼此具有外鍵的普通模型,並查看 makemigrations 如何解決該循環依賴。)
解決此問題的最佳方法是刪除表並刪除所有遷移文件,然后使用新創建的自定義模型重新運行遷移。 希望這會奏效。
有關如何從內置模型遷移到新模型的更多詳細信息,請訪問https://code.djangoproject.com/ticket/25313
我四處詢問,代碼應該在舊版本的 django 中工作。 遺憾的是它在 django 2.0 或更高版本中不起作用。 如果有人想要替代方案,我發現這非常適合我的項目,解釋也很簡單。
警告:它會刪除你的整個數據庫。 如果你有一些重要的數據,那就用dumpdata備份,然后用loaddata恢復。 有關更多信息,請查看此處(我不確定)。
在項目中途改變AUTH_USER_MODEL是非常困難的。 請參閱文檔中的注釋。 在您完成 Django 表的第一次遷移后感染,您將面臨問題。
想法是:你需要包括您的自定義用戶模型及其在setting.py在你第一次遷移的條目(AUTH_USER_MODEL = [自定義用戶模型])(Django在何處創建其自己的表像auth_group,dajango_migrations等)的姜戈項目。
警告:如果你已經啟動了服務器,那么 Django 自己會創建數據庫,然后這將不起作用,所以請不要啟動服務器。
完成了。
現在您可以啟動服務器了。
之后取消注釋所有其他模型並遷移它們。
對於 Django 2.2+:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.