4

I have created a custom user model (users_user) which works for registering new users (creating new custom user records) and logging in. But if I go to the Admin page, and try to delete a user record from there, it seems to be trying to delete records from the default user model (auth_user). I get the error:

IntegrityError at /admin/users/user/
insert or update on table "django_admin_log" violates foreign key constraint "django_admin_log_user_id_c564eba6_fk_auth_user_id"
DETAIL:  Key (user_id)=(3) is not present in table "auth_user".

Is there a way I can keep the standard Django Administration pages (screenshot below), but reference my custom user model instead of the standard auth_user model?

users/models.py

from django.db import models
from PIL import Image
from django.conf import settings
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)

#~~~ CUSTOM USER ~~~

class UserManager(BaseUserManager):
    def create_user(self, email, username, password=None):
        print('username in UserManager.create_user(): ' + username)

        if not email:
            raise ValueError('Users must have an email address')

        if not username:
            raise ValueError('Users must have a username')

        user = self.model(
            email=self.normalize_email(email),
            username=username, #todo: confirm, is this right?
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staffuser(self, email, password):
        """
        Creates and saves a staff user with the given email and password.
        """
        user = self.create_user(
            email,
            username=username,
            password=password,
        )
        user.staff = True
        user.save(using=self._db)
        return user

    def create_superuser(self, email, username, password):
        print('username in UserManager.create_superuser(): ' + username)
        """
        Creates and saves a superuser with the given email and password.
        """
        user = self.create_user(
            email,
            username=username,
            password=password,
        )
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user




class User(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    username = models.CharField(max_length=100, unique=True)
    is_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 is built in.

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email'] # Email & Password are required by default.

    objects = UserManager()


    def get_short_username(self):
        # The user is identified by their email address
        return self.username[0:10] # Get first 10 chars of username

    def __str__(self):
        return self.username

    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






class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')

    def __str__(self):
        return f'{self.user.username} Profile'

    # def save(self, *args, **kwargs):
    #     super().save(*args, **kwargs)

    #     img = Image.open(self.image.path)

    #     if img.height > 300 or img.width > 300:
    #         output_size = (300, 300)
    #         img.thumbnail(output_size)
    #         img.save(self.image.path)

users/admin.py:

from django.contrib import admin
from .models import Profile

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

admin.site.register(Profile)
admin.site.register(User) #<- THIS IS REGISTERING THE WRONG USER MODEL

enter image description here

Tom
  • 364
  • 2
  • 19
  • 2
    Did you already set your [AUTH_USER_MODEL](https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project)? – Brian Destura Jul 29 '21 at 04:34
  • 1
    Also, the error about django admin log might be a different problem. Have a look [here](https://stackoverflow.com/a/34109293/6759844) – Brian Destura Jul 29 '21 at 04:35
  • Kindly check [this](https://stackoverflow.com/questions/34109251/insert-or-update-on-table-django-admin-log-violates-foreign-key-constraint-whe/34109293#34109293), worked for me. Thank me later. – Kenneth mwangi Jan 12 '22 at 06:50

2 Answers2

0

I have a similar abstracted user model in a django application I am working on. This is how I have my admin.py setup and it works per your request.

I have modified your admin.py to look more like mine. I believe when you are using the 'get_user_model' function, it is causing the problem.

Also, unless you have a specific reason to add the fields email, username, is_active, staff. Subclassing the abstract user model already provides all of the default fields. I have added an additional field to foreign key a user to a profile type model. I use the UserAdmin model and field sets to display my custom user field in the django admin.

from django.contrib import admin

# Import your abstract user model from the apps models.py
from .models import Profile, User

# Import the auth UserAdmin model
from django.contrib.auth.admin import UserAdmin


# I use this to add the custom fields the django admin form, you may not need it. 
fields = list(UserAdmin.fieldsets)
fields[0] = (None, {'fields': ('username','password','account')})
UserAdmin.fieldsets = tuple(fields)

admin.site.register(Profile)
# Register the two models
admin.site.register(User, UserAdmin) 

For reference, here is what my models.py looks like for the user model.

class User(AbstractUser):
account = models.ForeignKey('Account', on_delete=models.PROTECT, null=True, blank=True, unique=True)

class Meta:
    permissions = (
                   ("make_admin", "Can view and edit most admin features."),
                   ("edit_permissions", "Admin user can modify user permissions."),
                   ("edit_nacha", "User can edit and modify NACHA files."),
                   ("edit_commissions", "User can override commisions."),
                   ("view_reports", "User can view admin reports."),
                  )
noes1s
  • 178
  • 1
  • 8
-1

You'll need to update your settings.py and point to the custom user model

settings.py

# Custom User model
AUTH_USER_MODEL = 'my_app.User'

admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from my_app.models import User

admin.site.register(User, UserAdmin)

See: https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#substituting-a-custom-user-model

jackotonye
  • 3,537
  • 23
  • 31