risper
risper

Reputation: 58

IntegrityError: FOREIGN KEY constraint failed

I am trying to post a form (ReviewForm) but I get the following error when my form tries to save:

FOREIGN KEY constraint failed

Here is my views.py code (the post function in the view class)

def post(self,request,*args,**kwargs):
    pk = self.kwargs.get("pk")
    di = self.kwargs.get("di")
    
    dis = get_object_or_404(Disease, pk=di)
    
    pestiside = Pestiside.objects.get(pk=pk, disease=dis)
           
    if request.method=='POST':
        user = request.user
        form= ReviewForm(request.POST)
        if form.is_valid():
            
            form.save()
            comment=form.cleaned_data.get('comment')
            new_review=Review.objects.create(author=user,pes_id=pestiside_id,comment=comment)
            new_review.save()  
        return redirect('diagnose:pestiside')       

Here is my models.py code:

class Review(models.Model):
    
  author= models.ForeignKey(User,default=1, on_delete=models.CASCADE)
  time = models.DateTimeField(auto_now_add=True, blank=True)
  pes = models.ForeignKey(Pestiside,default=0,on_delete=models.CASCADE)
  comment = models.CharField(max_length=200)

Here is my forms.py code:

class ReviewForm(forms.ModelForm):
    class Meta:
        model=Review
        fields=('comment',)

Here is my stacktrace, the error shows at form.save() in views.py:

Traceback (most recent call last):
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 396, in execute
    return Database.Cursor.execute(self, query, params)

The above exception (FOREIGN KEY constraint failed) was the direct cause of the following exception:
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/views/generic/base.py", line 71, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/views/generic/base.py", line 97, in dispatch
    return handler(request, *args, **kwargs)
  ***File "/home/risper/django_projects/Tomadoc/diagnose/views.py", line 276, in post
    form.save()***
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/forms/models.py", line 459, in save
    self.instance.save()
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/base.py", line 746, in save
    force_update=force_update, update_fields=update_fields)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/base.py", line 784, in save_base
    force_update, using, update_fields,
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/base.py", line 887, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/base.py", line 926, in _do_insert
    using=using, raw=raw,
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/query.py", line 1204, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1391, in execute_sql
    cursor.execute(sql, params)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
    return super().execute(sql, params)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
    return self.cursor.execute(sql, params)
  File "/home/risper/django_projects/env01/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 396, in execute
    return Database.Cursor.execute(self, query, params)

Exception Type: IntegrityError at /diagnose/pestiside/7/4
Exception Value: FOREIGN KEY constraint failed

Upvotes: 1

Views: 962

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476534

By saving the form, you save the new review, so manually saving it a second time will create a second review. The error however occurs when you save the form, since you never specified the pk for the disease or the user.

For Django, that is not a problem, since you specified default=0 and default=1, but it is not said that a User or Pestiside with that primary key exists. For most databases automatically generated primary keys start with one.

You should simply specify the values for the pestiside and user, so:

def post(self,request, *args, **kwargs):
    pk = self.kwargs['pk']
    di = self.kwargs['di']
    get_object_or_404(Pestiside, pk=pk, disease_id=di)
    if request.method=='POST':
        user = request.user
        form= ReviewForm(request.POST)
        if form.is_valid():
            form.author = request.user
            form.pes_id = pk
            form.save()
        return redirect('diagnose:pestiside')

As @Melvyn says, the class-based view will only call post in case it is a POST request, so there is no need to check this. You furthermore might want to use a class-based view like a CreateView [Django-doc] which can elminate a lot of boilerplate code:

from django.urls import reverse_lazy
from django.views.generic.edit import CreateView

class CreateReviewView(CreateView):
    model = Review
    form_class = ReviewForm
    sucess_url = reverse_lazy('diagnose:pestiside')
    
    def form_valid(self, form):
        form.author = self.request.user
        form.pes_id = self.kwargs['pk']
        return super().form_valid(form)

I would however simply not specify default values. It makes no sense to specify a default here, since you will need to determine the author and the Pestiside in the view. It is not guaranteed at all that objects with these primary keys will exist, not on the development database.

Upvotes: 2

SLDem
SLDem

Reputation: 2182

You dont need to create another instance of your Review class after submitting the form, form.save() does that for you, also you are not assigning your user to the instance that is being saved, try to write your function like shown below:

Instead of:

def post(self):
    ...

do this:

def form_valid(self, form): # you will need to make your view a FormView and define a form_class variable with ReviewForm
    review = form.save(commit=False)

    pk = self.kwargs.get("pk")
    di = self.kwargs.get("di")
    dis = get_object_or_404(Disease,pk=di)
    pestiside = Pestiside.objects.get(pk=pk, disease=dis)

    review.author = self.request.user
    review.pes = pestiside
    review.save()
    return redirect('diagnose:pestiside')

Upvotes: 1

Related Questions