Reputation: 58
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
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
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