FOREIGN KEY constraint failed - Any newly created superuser causes the error when attempting to modify a user

I’m well into development of this project, I have a version in production and everything is working fine over there.

I recently discovered that if I try to create a new superuser, the user is not functional. The user is successfully created, it appears in my admin panel, everything appears to be normal, I can log in with the user, but when logged in as that user I attempt to modify another user through the admin panel, such as change their password or email, my app crashes with a FOREIGN KEY constraint failed.

The error happens when:
I create a new superuser (through the admin panel or through createsuperuser or through the shell, I did test all 3), log onto that new user and attempt to modify another user through the admin panel. FOREIGN KEY constraint failed happens as soon as I hit save and the user is not modified.

The error doesn’t happen when:
I use my original development superuser to do the same operations.

My custom user model:

class Employee(AbstractUser):
    client = models.ForeignKey(Client,on_delete=models.CASCADE,blank=False,null=True,default=None)
    ROLE_CHOICES = {
        "OWNER": "Account owner (Head administrator)",
        "ADMIN": "Administrator",
        "USER": "User",
    }
    status = models.CharField(
        choices=ROLE_CHOICES,
        default="USER",
    )
    first_name = models.CharField(max_length=254,blank=False,default='Firstname')
    last_name = models.CharField(max_length=254,blank=False,default='Lastname')
    email = models.EmailField(max_length=254,blank=False,unique=True)
    flha_in_use = models.ManyToManyField(FLHA,blank=True)
    flha_templates = models.ManyToManyField(FLHATemplate,blank=True)
    class Meta:
        verbose_name = 'Employee'
        verbose_name_plural = 'Employees'
    def __str__(self):
        return self.get_full_name()

The only ForeignKey is the custom model ‘Client’:

class Client(Group):
    flha = models.ManyToManyField(FLHA,blank=True)
    flha_templates = models.ManyToManyField(FLHATemplate,blank=True)

When I manually add a client through the shell, the error still happens.
When I add the client by modifying the user through the admin panel (using my original, functioning superuser), the client is updated successfully, I then log onto that user and the error still happens.

The error message:

|Django Version:|5.2.1|
| --- | --- |
|Exception Type:|IntegrityError|
|Exception Value:|FOREIGN KEY constraint failed|
|Exception Location:|C:\...\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\backends\base\base.py, line 303, in _commit|
|Raised during:|django.contrib.admin.options.change_view|
|Python Executable:|C:\...\AppData\Local\Programs\Python\Python313\python.exe|
|Python Version:|3.13.3|
|Python Path:|```
['C:\\...\\Documents\\GitHub\\cs\\dev\\server',
 'C:\\...\\AppData\\Local\\Programs\\Python\\Python313\\python313.zip',
 'C:\\...\\AppData\\Local\\Programs\\Python\\Python313\\DLLs',
 'C:\\...\\AppData\\Local\\Programs\\Python\\Python313\\Lib',
 'C:\\...\\AppData\\Local\\Programs\\Python\\Python313',
 'C:\\...\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages']
```|

The traceback:

Environment:


Request Method: POST
Request URL: http://localhost:8000/admin/flowforms/employee/2/change/

Django Version: 5.2.1
Python Version: 3.13.3
Installed Applications:
['flowforms.apps.FlowformsConfig',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
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\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\backends\base\base.py", line 303, in _commit
    return self.connection.commit()
           ^^^^^^^^^^^^^^^^^^^^^^^^

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\contrib\admin\options.py", line 719, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\utils\decorators.py", line 192, in _view_wrapper
    result = _process_exception(request, e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\utils\decorators.py", line 190, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\views\decorators\cache.py", line 80, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\contrib\admin\sites.py", line 246, in inner
    return view(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\contrib\admin\options.py", line 1987, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\utils\decorators.py", line 48, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\utils\decorators.py", line 192, in _view_wrapper
    result = _process_exception(request, e)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\utils\decorators.py", line 190, in _view_wrapper
    response = view_func(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\contrib\admin\options.py", line 1842, in changeform_view
    with transaction.atomic(using=router.db_for_write(self.model)):
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\transaction.py", line 263, in __exit__
    connection.commit()
    ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\utils\asyncio.py", line 26, in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\backends\base\base.py", line 327, in commit
    self._commit()
    ^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\backends\base\base.py", line 302, in _commit
    with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Adminator\AppData\Local\Programs\Python\Python313\Lib\site-packages\django\db\backends\base\base.py", line 303, in _commit
    return self.connection.commit()
           ^^^^^^^^^^^^^^^^^^^^^^^^

Exception Type: IntegrityError at /admin/flowforms/employee/2/change/
Exception Value: FOREIGN KEY constraint failed

Does anyone have any clue as to what might be happening here?
Or potential solutions?

The inability to create a new superuser should something go wrong with the old one is truly a problem.

Welcome @cerealc0de !

Please post your Model Admin class for the Employee model.

Here you go:

class EmployeeAdmin(UserAdmin):
    ordering = ['first_name','last_name']
    list_display = ("username",'client','first_name','last_name','email','status','is_staff','is_superuser')
    fieldsets = (
        ("Credentials", {"fields": ("username","password")}),
        ("Employee Info", {"fields": ('client',"email",'status')}),
        ("Permissions", {"fields": ("is_staff","is_superuser")}),
    )
    add_fieldsets = (
        ("Credentials", { 'classes': ('wide',), "fields": ('username','password1','password2')}),
        ("Employee Info", { 'classes': ('wide',), "fields": ('client','first_name','last_name','email','status')}),
    )
from .models import Employee
admin.site.register(Employee, EmployeeAdmin)

Update:

My production server is not having this issue. I just re-confirmed to make sure. I can create new superusers and use them to modify other users, I encounter no issue.

I pulled my models.py, admin.py and migrations from my production files.

Functional models.py:

class Employee(AbstractUser):
    client = models.ForeignKey(Client,on_delete=models.CASCADE,null=True)
    first_name = models.CharField(max_length=254,blank=False)
    last_name = models.CharField(max_length=254,blank=False)
    email = models.EmailField(max_length=254,blank=False)
    flha_in_use = models.ManyToManyField(FLHA,blank=True)
    flha_templates = models.ManyToManyField(FLHATemplate,blank=True)
    class Meta:
        verbose_name = 'Employee'
        verbose_name_plural = 'Employees'
    def __str__(self):
        return self.get_full_name()

Functional admin.py:

class EmployeeAdmin(UserAdmin):
    ordering = ['first_name','last_name']
    list_display = ("username",'client','first_name','last_name','email','is_staff','is_superuser')
    fieldsets = (
        ("Credentials", {"fields": ("username","password")}),
        ("Employee Info", {"fields": ("client","first_name","last_name","email")}),
        ("Permissions", {"fields": ("is_active","is_staff","is_superuser")}),
    )
    add_fieldsets = (
        ("Credentials", { 'classes': ('wide',), "fields": ('username','password1','password2')}),
        ("Employee Info", { 'classes': ('wide',), "fields": ('client','first_name','last_name','email')}),
    )
from .models import Employee
admin.site.register(Employee, EmployeeAdmin)

I pulled the local dev db from a backup I made long before the last functional production deploy, I ran the current version of the migrations and models on that local db to bring it up to date.
I then created a superuser through the admin panel, went fine.
I then used that user to try and modify another user: FOREIGN KEY constraint failed

How is this possible? I rolled back everything related to the database to a version I know is functional, but the same error still happens. Any ideas on what else I can try? I have no idea where the issue might be and I simply cannot push anything to production until it is cleared out, I can’t risk corrupting my production database.

I have tried to remove the ForeignKey field from the Employee model entirely.
Still getting that same error.
I can’t seem to figure out which ForeignKey seems to be having issues.

I did find this mention of constraints in the documentation:

ForeignKey.db_constraint[¶](https://docs.djangoproject.com/en/5.2/ref/models/fields/#django.db.models.ForeignKey.db_constraint)

Controls whether or not a constraint should be created in the database for this foreign key. The default is `True`, and that’s almost certainly what you want; setting this to `False` can be very bad for data integrity. That said, here are some scenarios where you might want to do this:

* You have legacy data that is not valid.
* You’re sharding your database.

If this is set to `False`, accessing a related object that doesn’t exist will raise its `DoesNotExist` exception.

Which doesn’t seem to explain how a constraint functions or how to solve constraint failures.
It does seem to point to the fact that some of the data in the database is no longer valid, but that really doesn’t explain why exactly I can operate normally on a user with my original superuser, but that any new superuser created is causing an integrity error.

Could it be some kind of data integrity check that tries to compare the db with what it believes the db should be? Some sort of security feature maybe?

The production server is running on the same version of everything, except python.
Production is on py 3.12, while dev is on 3.13.3.

I don’t really know what’s going on but is it possible that you swapped the user model (changed AUTH_USER_MODEL) and you still have some tables which reference the original auth_user table instead of your new Employee user model?

Maybe it would also be useful to know which exact SQL query triggers the failure. You could try logging all SQL queries and looking at the last of them:

Or maybe inspect the database schema and see if foreign key constraints match your expectations.

I believe that’s the case.

I did find this other thread that seems to be the exact same issue as mine, where someone pointed out that running the first migration before changing AUTH_USER_MODEL can be the cause.

When I first built the database, I had to work around a certain issue, as a result I ran the first migration before changing AUTH_USER_MODEL. There’s likely an empty user table in the database, which would explain why it doesn’t matter how far back I pull my backup from, and would also explain why the production database is not having the issue (AUTH_USER_MODEL was configured before the first migration).

I did try to generate a superuser by manually creating specifically an Employee through the shell, constraint still failed. That part I found very strange, because both the target user and the admin user were created as an Employee object specifically. If the issue really is coming from the AUTH_USER_MODEL not being configured before the first migration, it sounds like it’s a django issue that should be addressed.

I’ll be investigating this potential cause a bit further and reporting back here.
I’m probably just going to end up rebuilding the local database if I can’t find an answer very soon though, I do have deadlines and this issue has cost me 2 days of productivity.

Sorry to hear that.

As an aside, I think it’s good to have an easy way to import a (preferrably anonymized) version of the production database into the local development environment. I do this all the time. When setting up a new project I basically immediately also set up a production or preview environment and manually enter test data there only if possible, never locally. Doing this work multiple times is just plain annoying (especially because I’m on a different computer when I’m working at the office…)

I ended up rebuilding the local database from scratch. The issue has been resolved.

This should be addressed in the tutorial/documentation. Django is having issues when the first migration is run before AUTH_USER_MODEL is set. It’s not something that can be guessed, especially since django naturally lets you modify this setting without providing any kind of warning.

What should also be addressed is the issue that led me to running the first migration before changing the AUTH_USER_MODEL. When running the migration with AUTH_USER_MODEL already set, django was failing to migrate. I don’t remember the specific error, but it was something about django not finding the custom user model. It turns out that the solution is to add this piece of code to the migration that creates the custom user model:

run_before = [
        ('admin', '__first__'),
    ]

Only after adding this to my custom user migration file was I able to run migrations with the AUTH_USER_MODEL already set. I found this solution in a stack overflow thread, it was nowhere in the django documentation/tutorial. It absolutely should be in the official documentation.

Pulling the database from production into local might be helpful, but I have no means of doing that at the moment and it isn’t really critical for my case. Either way, I use sqlite for dev and postgres for prod, and I don’t really know how I would pull from one to the other (though I’m sure there are ways).

It is: Extending the User Model

Specifically, in the section: Changing to a custom user model mid-project.

This section I had originally read when trying to solve this problem, however it really just gives broad information while lacking certain important specific points.

First, as my database was functional (and it took the creation of a new superuser to find the problem), I had assumed that the method I had used worked. I have been using this database for about 4 months without encountering any issues until now. I think it should be important to mention that it will create those issues down the line specifically if the migration is not run after the AUTH_USER_MODEL is set. This is a very important detail that is not mentioned. Running a first migration to generate the database, then immediately setting the AUTH_USER_MODEL seemed fine, it didn’t exactly seem to be the same as changing it mid-project as the documentation states, but it apparently causes issues regardless. I think specifically stating that AUTH_USER_MODEL should be set before the first migration is important and it isn’t clear at all from the documentation.

Second, my custom user has a ForeignKey attribute based on another custom model. When I first tried migrating with my custom user model in the first migration, it would fail, stating a dependency issue. It led me to putting the custom user model in the second migration. Which is what led me to my janky solution of running a first migration before changing the AUTH_USER_MODEL in the first place. An easy solution to enable properly generating a custom user model past the first migration, is to include this piece of code:

run_before = [
        ('admin', '__first__'),
    ]

This is also not mentioned in any way at all, while being crucial information. If at least the mention of migration variables was in there somewhere, something could be deduced or explored, but there is no link or hint at these. In fact, if you go to this link: Migration Operations | Django documentation | Django
and ctrl+f ‘run_before’, you get zero results.
If you google ‘run_before django’ you will find this page: How to create database migrations | Django documentation | Django
where ‘run_before’ is mentioned in the migration order control section.
If you go back to the first link: Migration Operations | Django documentation | Django and ctr+f ‘order’, you find nothing regarding migration order control. Not even a link to the page mentioning ‘run_before’.

This type of documentation is obviously massive and difficult to organize optimally, that I understand. However, I think this particular section on changing AUTH_USER_MODEL could benefit tremendously from a specific mention of this one particular requirement for database integrity: setting AUTH_USER_MODEL before any migration is run. It could also benefit tremendously from at least a link pointing to the migration operation pages, stating that these migration operations do exist and can potentially be used to troubleshoot further issues with custom user model. This at least would give you an idea of where to look.