簡體   English   中英

創建/編輯/刪除用戶時,django 管理面板中的 FOREIGN KEY 約束失敗。 (使用自定義用戶模型。)

[英]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 自己會創建數據庫,然后這將不起作用,所以請不要啟動服務器。

  • 刪除 dbsqlite3 數據庫文件,刪除除 init 文件之外的所有遷移文件及其二進制文件(在 app/migration/ pycache 中),並注釋掉所有模型及其依賴項(例如,您以任何形式使用模型,然后也對其進行注釋)。
  • 現在僅取消注釋自定義用戶模型
  • 在 setting.py 中添加 AUTH_USER_MODEL (AUTH_USER_MODEL = [自定義用戶模型])
  • 然后運行 ​​makemigrations 並遷移。 (這將創建您的所有 Django 表和您的自定義用戶模型。)

完成了。

現在您可以啟動服務器了。

之后取消注釋所有其他模型並遷移它們。

對於 Django 2.2+:

  1. 如果是測試數據 -> 那么您必須從所有應用程序和項目中刪除所有遷移和 pycache 文件夾,並同時刪除“db.sqlite3”文件。
  2. 進行遷移並遷移應用程序,然后它就可以工作了。 (我有同樣的問題,它使用這種方法工作。)
  3. 如果數據是導入的,您可以使用fixtures google it輕松備份數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM