Django 2.0: sqlite IntegrityError: FOREIGN KEY constraint failed
Question:
I’m working on adding Django 2.0 support to the django-pagetree library. During automated testing, using an sqlite in-memory database, I’m getting a bunch of errors like this:
File "/home/nnyby/src/django-pagetree/pagetree/tests/test_models.py", line 638, in setUp
'children': [],
File "/home/nnyby/src/django-pagetree/pagetree/models.py", line 586, in add_child_section_from_dict
...
File "/home/nnyby/src/django-pagetree/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 239, in _commit
return self.connection.commit()
django.db.utils.IntegrityError: FOREIGN KEY constraint failed
This is noted in the Django 2.0 release notes: https://docs.djangoproject.com/en/2.0/releases/2.0/#foreign-key-constraints-are-now-enabled-on-sqlite
From that description, which I don’t fully understand, this shouldn’t apply for test databases that aren’t persistent, right? Wouldn’t my sqlite test db get created with the appropriate options when using Django 2.0?
The app settings I’m using for testing are here: https://github.com/ccnmtl/django-pagetree/blob/master/runtests.py
Answers:
Do you have add on_delete to your FOREIGN KEY? On Django 2.0 this argument is required.
You could see also:
https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.on_delete
https://docs.djangoproject.com/en/2.0/howto/upgrade-version/
https://docs.djangoproject.com/en/2.0/topics/db/examples/many_to_one/
https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey
The documentation says two things:
-
If you have ForeignKey constraints they are now enforced at the database level. So make sure you’re not violating a foreign key constraint. That’s the most likely cause for your issue, although that would mean you’d have seen these issues with other databases. Look for patterns like this in your code:
# in pagetree/models.py, line 810
@classmethod
def create_from_dict(cls, d):
return cls.objects.create() # what happens to d by the way?
This will definitely fail with a ForeignKey constraint error since a PageBlock
must have section
, so you can’t call create
without first assigning it.
-
If you circumvent the foreign key constraint by performing an atomic transaction (for example) to defer committing the foreign key, your Foreign Key needs to be INITIALLY DEFERRED. Indeed, your test db should already have that since it’s rebuilt every time.
I met a different situation with the same error. The problem was that I used the same Model name and field name
Incorrect code:
class Column(models.Model):
...
class ColumnToDepartment(models.Model):
column = models.ForeignKey(Column, on_delete=models.CASCADE)
Solution:
class Column(models.Model):
...
class ColumnToDepartment(models.Model):
referring_column = models.ForeignKey(Column, on_delete=models.CASCADE)
I just had this error: sqlite3.IntegrityError: FOREIGN KEY constraint failed
on my Django project. Turns out I deleted the migrations folder somewhere along the line so it didn’t pick up my model changes when I ran python manage.py makemigrations
. Just make sure you still have a migrations folder with migrations in.
One more thing to check, in my case it was related to my fixtures files.
Regenerating them after migration to Django3 solved the issue I had while testing my app.
./manage.py dumpdata app.Model1 app.Model2 --indent=4 > ./app/fixtures/file.json
When I have trouble with migrations or tables, I do it and it very often helps:
- Comment your trouble strings;
- Do
python3 manage.py makemigrations
and python3 manage.py migrate
;
- Then u must do
python3 manage.py migrate --fake
;
- Uncomment your strings and do it again
python3 manage.py makemigrations
and python3 manage.py migrate
.
I hope it is useful for u
In my case, I found that the ForeignKey object that my model refers to does not exist.
Therefore, I change the referenced FK object to the existing object.
My problem was solved after doing the migration, because I have altered the foreign key and then didn’t apply the migrations.
Specifically, at first I have the following piece of code in models:
class TeacherRequest(models.Model):
requester = models.ForeignKey(
Profile,
on_delete=models.CASCADE,
related_name="teacher_request",
)
class RequestStatus(models.TextChoices):
PENDING = '1', _('pending')
APPROVED = '2', _('approved')
REJECTED = '3', _('rejected')
status = models.CharField(
choices=RequestStatus.choices,
max_length=1,
default=RequestStatus.PENDING,
)
Then I have changed the foreign key from Profile
to User
:
class TeacherRequest(models.Model):
requester = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="teacher_request",
)
class RequestStatus(models.TextChoices):
PENDING = '1', _('pending')
APPROVED = '2', _('approved')
REJECTED = '3', _('rejected')
status = models.CharField(
choices=RequestStatus.choices,
max_length=1,
default=RequestStatus.PENDING,
)
Solution
python manage.py makemigrations
python manage.py migrate
A reason could be you miscalculated what happens when you delete an item from the db that is linked with a foreign key to something else, elsewhere.
p.e. what happens when you delete an author that has active books?
I don’t meant to enter into the logic of the application, but consider for example to cascade
the deletion of the elements linked to that key.
Here is an example, in this case we are dealing with "post" attribute for each "user"
user = models.ForeignKey(User, related_name='posts', on_delete=models.CASCADE)
Here’s a careful explanation, Django 4.0:
https://docs.djangoproject.com/en/4.0/ref/models/fields/
Most probably the cause of the error is the lacking of matching Foreignkey elements in your model and the one your trying to save(update using that foreignkey).
Make sure that the foreignkey constraints(value) are present in both your and the new data
I’m working on adding Django 2.0 support to the django-pagetree library. During automated testing, using an sqlite in-memory database, I’m getting a bunch of errors like this:
File "/home/nnyby/src/django-pagetree/pagetree/tests/test_models.py", line 638, in setUp
'children': [],
File "/home/nnyby/src/django-pagetree/pagetree/models.py", line 586, in add_child_section_from_dict
...
File "/home/nnyby/src/django-pagetree/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 239, in _commit
return self.connection.commit()
django.db.utils.IntegrityError: FOREIGN KEY constraint failed
This is noted in the Django 2.0 release notes: https://docs.djangoproject.com/en/2.0/releases/2.0/#foreign-key-constraints-are-now-enabled-on-sqlite
From that description, which I don’t fully understand, this shouldn’t apply for test databases that aren’t persistent, right? Wouldn’t my sqlite test db get created with the appropriate options when using Django 2.0?
The app settings I’m using for testing are here: https://github.com/ccnmtl/django-pagetree/blob/master/runtests.py
Do you have add on_delete to your FOREIGN KEY? On Django 2.0 this argument is required.
You could see also:
https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.on_delete
https://docs.djangoproject.com/en/2.0/howto/upgrade-version/
https://docs.djangoproject.com/en/2.0/topics/db/examples/many_to_one/
https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey
The documentation says two things:
-
If you have ForeignKey constraints they are now enforced at the database level. So make sure you’re not violating a foreign key constraint. That’s the most likely cause for your issue, although that would mean you’d have seen these issues with other databases. Look for patterns like this in your code:
# in pagetree/models.py, line 810 @classmethod def create_from_dict(cls, d): return cls.objects.create() # what happens to d by the way?
This will definitely fail with a ForeignKey constraint error since a
PageBlock
must havesection
, so you can’t callcreate
without first assigning it. -
If you circumvent the foreign key constraint by performing an atomic transaction (for example) to defer committing the foreign key, your Foreign Key needs to be INITIALLY DEFERRED. Indeed, your test db should already have that since it’s rebuilt every time.
I met a different situation with the same error. The problem was that I used the same Model name and field name
Incorrect code:
class Column(models.Model):
...
class ColumnToDepartment(models.Model):
column = models.ForeignKey(Column, on_delete=models.CASCADE)
Solution:
class Column(models.Model):
...
class ColumnToDepartment(models.Model):
referring_column = models.ForeignKey(Column, on_delete=models.CASCADE)
I just had this error: sqlite3.IntegrityError: FOREIGN KEY constraint failed
on my Django project. Turns out I deleted the migrations folder somewhere along the line so it didn’t pick up my model changes when I ran python manage.py makemigrations
. Just make sure you still have a migrations folder with migrations in.
One more thing to check, in my case it was related to my fixtures files.
Regenerating them after migration to Django3 solved the issue I had while testing my app.
./manage.py dumpdata app.Model1 app.Model2 --indent=4 > ./app/fixtures/file.json
When I have trouble with migrations or tables, I do it and it very often helps:
- Comment your trouble strings;
- Do
python3 manage.py makemigrations
andpython3 manage.py migrate
; - Then u must do
python3 manage.py migrate --fake
; - Uncomment your strings and do it again
python3 manage.py makemigrations
andpython3 manage.py migrate
.
I hope it is useful for u
In my case, I found that the ForeignKey object that my model refers to does not exist.
Therefore, I change the referenced FK object to the existing object.
My problem was solved after doing the migration, because I have altered the foreign key and then didn’t apply the migrations.
Specifically, at first I have the following piece of code in models:
class TeacherRequest(models.Model):
requester = models.ForeignKey(
Profile,
on_delete=models.CASCADE,
related_name="teacher_request",
)
class RequestStatus(models.TextChoices):
PENDING = '1', _('pending')
APPROVED = '2', _('approved')
REJECTED = '3', _('rejected')
status = models.CharField(
choices=RequestStatus.choices,
max_length=1,
default=RequestStatus.PENDING,
)
Then I have changed the foreign key from Profile
to User
:
class TeacherRequest(models.Model):
requester = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="teacher_request",
)
class RequestStatus(models.TextChoices):
PENDING = '1', _('pending')
APPROVED = '2', _('approved')
REJECTED = '3', _('rejected')
status = models.CharField(
choices=RequestStatus.choices,
max_length=1,
default=RequestStatus.PENDING,
)
Solution
python manage.py makemigrations
python manage.py migrate
A reason could be you miscalculated what happens when you delete an item from the db that is linked with a foreign key to something else, elsewhere.
p.e. what happens when you delete an author that has active books?
I don’t meant to enter into the logic of the application, but consider for example to cascade
the deletion of the elements linked to that key.
Here is an example, in this case we are dealing with "post" attribute for each "user"
user = models.ForeignKey(User, related_name='posts', on_delete=models.CASCADE)
Here’s a careful explanation, Django 4.0:
https://docs.djangoproject.com/en/4.0/ref/models/fields/
Most probably the cause of the error is the lacking of matching Foreignkey elements in your model and the one your trying to save(update using that foreignkey).
Make sure that the foreignkey constraints(value) are present in both your and the new data