IntegrityError: New admin user can't edit in the Dashboard

I am currently facing a very strange error and don’t know what to do.

Summary

As my first Django project I am currently programming a website for a betting game. I manage a large part of the data in the database with the Django admin dashboard for the sake of simplicity.
Up to now I have always managed the data for tests with my first created superuser. Without any problems. Now I have deployed the website and created a second admin user. However, this user cannot make any changes/creations/deletions to any database via the admin dashboard. There is always an IntegrityError: FOREIGN KEY constraint failed (details below).

:clipboard: What I tried:

  • I gave admin rights to the user
  • I explicitly gave him all change rights again
  • I created the second admin user again with “manage.py createsuperuser”

:person_in_tuxedo: CustomUser Model

Maybe it is important to know that I created a custom user model, which is also registered in settings.py.

I noticed that after the error when reloading the page, the changes/deletions etc. were not applied, but the success message is displayed: “xxxx changed successfully :white_check_mark:”.

As I said, Django is still relatively new to me. So please let me know what other information might be important and I will provide it.
Thanks for your time helping me

:x::fire::fire:Error Details

Environment:

Request Method: POST
Request URL: http://localhost:8000/admin/main/match/18/change/

Django Version: 5.0.6
Python Version: 3.11.7
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'crispy_forms',
 'crispy_bootstrap5',
 'main.apps.MainConfig',
 'account.apps.AccountConfig']
Installed 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']



Traceback (most recent call last):
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 299, in _commit
    return self.connection.commit()
           ^^^^^^^^^^^^^^^^^^^^^^^^

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\options.py", line 716, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 188, in _view_wrapper
    result = _process_exception(request, e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 186, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\views\decorators\cache.py", line 80, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\sites.py", line 240, in inner
    return view(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\options.py", line 1948, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 48, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 188, in _view_wrapper
    result = _process_exception(request, e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 186, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\options.py", line 1803, in changeform_view
    with transaction.atomic(using=router.db_for_write(self.model)):
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\transaction.py", line 263, in __exit__
    connection.commit()
    ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\asyncio.py", line 26, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 323, in commit
    self._commit()
    ^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 298, in _commit
    with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 299, in _commit
    return self.connection.commit()
           ^^^^^^^^^^^^^^^^^^^^^^^^

Exception Type: IntegrityError at /admin/main/match/18/change/
Exception Value: FOREIGN KEY constraint failed

CustomUser from models.py

class CustomUser(AbstractUser):
    meistertipp = models.ForeignKey(Mannschaft, related_name='meistertipp_users', null=True, blank=True, on_delete=models.CASCADE)
    koenigtipp = models.ForeignKey(Mannschaft, related_name='koenigtipp_users', null=True, blank=True, on_delete=models.CASCADE)
    p_1 = models.IntegerField(default=0)
    p_2 = models.IntegerField(default=0)
    p_3 = models.IntegerField(default=0)
    p_4 = models.IntegerField(default=0)
    p_5 = models.IntegerField(default=0)
    p_total = models.IntegerField(default=0)

    def __str__(self):
        return self.username

settings.py

...
AUTH_USER_MODEL = 'main.CustomUser'
...

Welcome @samuelx12 !

The url showing the error identifies the error as being caused during an attempt to edit a “Match” object. That’s where we probably need to start with this. Please post your Match model.

Thank you for your response! :pray:

Unfortunately, this error occurs regardless of which table the new admin user wants to change. But you are right, maybe it helps to see the models of the different tables.

However, how could it be explained that if there is an error in the models, my original admin user can make changes and the newly created one cannot?
I know it’s really weird.

However here is the requested code:

models.py

Sorry for the German in the code. It’s there so that non-English speakers can also navigate the admin dashboard. I tried to translate everything in the comments.

from django.contrib.auth.models import AbstractUser
from django.db import models


class Mannschaft(models.Model):  # Model for the Teams / Countries
    name = models.CharField(max_length=100)
    unausgeschieden = models.BooleanField()

    def __str__(self):
        return self.name

    def get_all_matches(self):
        als_1 = self.match_als_1.all()
        als_2 = self.match_als_2.all()

        return als_1 | als_2  # Merges the QuerySets


class CustomUser(AbstractUser):  # Custom User Model
    # Tips for the world champion and the country of the top scorer
    meistertipp = models.ForeignKey(Mannschaft, related_name='meistertipp_users', null=True, blank=True, on_delete=models.CASCADE)
    koenigtipp = models.ForeignKey(Mannschaft, related_name='koenigtipp_users', null=True, blank=True, on_delete=models.CASCADE)
    # Points during the 5 stages
    p_1 = models.IntegerField(default=0)
    p_2 = models.IntegerField(default=0)
    p_3 = models.IntegerField(default=0)
    p_4 = models.IntegerField(default=0)
    p_5 = models.IntegerField(default=0)
    p_total = models.IntegerField(default=0)

    def __str__(self):
        return self.username


class Match(models.Model):
    datumzeit = models.DateTimeField()  # Time
    ort = models.CharField(max_length=100)  # Place
    mannschaft1 = models.ForeignKey(Mannschaft, related_name='match_als_1', on_delete=models.CASCADE, null=True, blank=True)  # Team 1
    tore1 = models.IntegerField(null=True, blank=True)  # Number of Goals of Team 1
    mannschaft2 = models.ForeignKey(Mannschaft, related_name='match_als_2', on_delete=models.CASCADE, null=True, blank=True)  # Team 2
    tore2 = models.IntegerField(null=True, blank=True)  # Goals2
    ko_spiel = models.BooleanField()  # if it is a knock-out game
    tipp_etappe = models.IntegerField()  # Which stage of the betting game the match belongs to
    platz_id = models.IntegerField(unique=True)  # Place of the game in the match schedule
    name = models.CharField(max_length=100, null=True, blank=True)  # Name of the Match (Final, semi-final)
    ausgang = models.IntegerField(null=True, blank=True)  # Outcome of the game (1=Team 1 wins, 2=Team 2 wins, 3=Draw)
    verlaengerung = models.BooleanField(default=False)  # if there was extra time
    # How the game ended in extra time (only the results after 90 minutes are decisive for the tips)
    verlaengerung_msg = models.CharField(max_length=200, null=True, blank=True)

    def __str__(self):
        if self.name:
            str_name = f" ({self.name})"
        else:
            str_name = ""
        return f"Match: {self.mannschaft1} vs. {self.mannschaft2}{str_name} (Resultat: {self.tore1}: {self.tore2}, {self.ausgang})"


class Tipp(models.Model):  # Tip
    match = models.ForeignKey(Match, on_delete=models.CASCADE)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    tore1 = models.IntegerField(null=True, blank=True)  # Goals of Team 1
    tore2 = models.IntegerField(null=True, blank=True)  # Goals of Team 2
    ausgang = models.IntegerField(null=True, blank=True)  # Outcome

    def __str__(self):
        return f"Tipp von {self.user.username} zu {self.match}"


# Not used, should have been a list of the possible top scorers
class TSKK(models.Model):  # TSKK = Torschützenkönigskandidat
    mannschaft = models.ForeignKey(Mannschaft, on_delete=models.CASCADE)
    tore = models.IntegerField()


class Einstellung(models.Model):  # Settings, maybe not the best way to save them
    eigenschaft = models.CharField(max_length=100)  # Properity
    wert = models.CharField(max_length=100)  # Value

    def __str__(self):
        return self.eigenschaft + ": " + self.wert


class Gruppe(models.Model):  # Group
    name = models.CharField(max_length=100)  # Name of the Group (Group A, Group B etc.)
    nr = models.IntegerField(unique=True, null=True)  # Number of the Group (Group A = 1, Group B = 2)
    # The ranking of the groupe
    p1 = models.IntegerField()  # 1st Place with p1 points is Team m1
    m1 = models.ForeignKey(Mannschaft, on_delete=models.CASCADE, related_name="gruppe_m1")
    p2 = models.IntegerField()
    m2 = models.ForeignKey(Mannschaft, on_delete=models.CASCADE, related_name="gruppe_m2")
    p3 = models.IntegerField()
    m3 = models.ForeignKey(Mannschaft, on_delete=models.CASCADE, related_name="gruppe_m3")
    p4 = models.IntegerField()
    m4 = models.ForeignKey(Mannschaft, on_delete=models.CASCADE, related_name="gruppe_m4")

    def __str__(self):
        return self.name


class Gruppentipp(models.Model):  # Tip for the group winners
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)  # the user which made this tip
    gruppe = models.ForeignKey(Gruppe, on_delete=models.CASCADE)  # group
    mannschaft = models.ForeignKey(Mannschaft, on_delete=models.CASCADE)  # which team wins this group

    def __str__(self):
        return f"{self.user} tippt {self.mannschaft} als Sieger von {self.gruppe.name}"

Example of an other error while trying to add something to the tips-table

Environment:


Request Method: POST
Request URL: http://localhost:8000/admin/main/tipp/add/

Django Version: 5.0.6
Python Version: 3.11.7
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'crispy_forms',
 'crispy_bootstrap5',
 'main.apps.MainConfig',
 'account.apps.AccountConfig']
Installed 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']



Traceback (most recent call last):
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 299, in _commit
    return self.connection.commit()
           ^^^^^^^^^^^^^^^^^^^^^^^^

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\options.py", line 716, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 188, in _view_wrapper
    result = _process_exception(request, e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 186, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\views\decorators\cache.py", line 80, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\sites.py", line 240, in inner
    return view(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\options.py", line 1945, in add_view
    return self.changeform_view(request, None, form_url, extra_context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 48, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 188, in _view_wrapper
    result = _process_exception(request, e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\decorators.py", line 186, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\contrib\admin\options.py", line 1803, in changeform_view
    with transaction.atomic(using=router.db_for_write(self.model)):
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\transaction.py", line 263, in __exit__
    connection.commit()
    ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\utils\asyncio.py", line 26, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 323, in commit
    self._commit()
    ^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 298, in _commit
    with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Samuel\PycharmProjects\Tippspiel-Website\.venv\Lib\site-packages\django\db\backends\base\base.py", line 299, in _commit
    return self.connection.commit()
           ^^^^^^^^^^^^^^^^^^^^^^^^

Exception Type: IntegrityError at /admin/main/tipp/add/
Exception Value: FOREIGN KEY constraint failed

Workaround

Since all models could no longer be edited by new admin users, but everything worked with my original admin user, I suspected the error was not in my database setup, but in the log function of Django admin.
So I deactivated the log function and the error no longer appeared.

Even though my problem has been solved so far, the question remains: What have I done wrong, incorrectly configured? Could it even be a bug in Django (which I think is rather unlikely)?
I would be happy to provide further information to clarify this.

My workaround

It’s probably not the best solution, but i hope it can help you, if you have the same problem.

# your_app/admin.py
from django.contrib import admin
from django.contrib.admin import ModelAdmin
from .models import YourModel1, YourModel2, YourModel3


class NoLogModelAdmin(ModelAdmin):
    def log_addition(self, request, object, message):
        pass  # Disables logging of additions

    def log_change(self, request, object, message):
        pass  # Disables logging of changes

    def log_deletion(self, request, object, object_repr):
        pass  # Disables logging of deletions


admin.site.register(Match, YourModel1)
admin.site.register(Tipp, YourModel2)
admin.site.register(TSKK, YourModel3)

This code disables logging of additions, changes, and deletions in Django’s admin interface for all models within an app. A custom NoLogModelAdmin class is defined, inheriting from admin.ModelAdmin, and overrides the log_addition, log_change, and log_deletion methods to prevent log entries from being created. All model-specific admin classes then inherit from this NoLogModelAdmin class, effectively disabling the logging functionality for all registered models.

This type of situation is frequently caused by changing from the standard user to a custom user after having run the initial migration.