I've made a django form in which I want to pass some context I need to display (mainly database entries in tags so the user can choose from them). I therefor made a get_context_data function
where I add the context to the existing context like this:
def get_context_data(self, **kwargs):
context = super(UploadView, self).get_context_data(**kwargs)
context['categories'] = Category.objects.all()
context['form'] = VideoForm
return context
however, the form is not saving the information passed to the database. Why would that not work?
Here is part of my code!
forms.py:
class VideoForm(forms.ModelForm):
category = forms.ModelChoiceField(queryset=Category.objects.all(), empty_label=None)
class Meta:
model = Video
fields = [
'title',
'description',
'description_short',
'category',
'time',
'thumbnail',
'type',
]
def clean_thumbnail(self):
picture = self.cleaned_data.get("thumbnail")
if not picture:
raise forms.ValidationError("No Image")
else:
w, h = get_image_dimensions(picture)
if w/h != (16/9):
raise forms.ValidationError("Image in wrong aspect ratio (should be 16:9)")
return picture
upload.html (it's pretty long so it's better to upload it to Pastebin)
views.py:
class UploadView(LoginRequiredMixin, CreateView):
form_class = VideoForm
template_name= 'upload.html'
def form_valid(self, form):
instance = form.save(commit=False)
instance.uploader=self.request.user
return super(UploadView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(UploadView, self).get_context_data(**kwargs)
context['categories'] = Category.objects.all()
context['form'] = VideoForm
return context
I'm using a custom form so I can set classes which I use for editing the CSS (instead of just using form.as_p and having a really ugly from there...)
EDIT:
After a bit more testing I found that if I put print(instance)
inside the def form_valid(self, form):
function it would not print out anything, suggesting the instance is empty. How can this be? Also, I tried removing: context['form'] = VideoForm
and no errors show up but if I fill in the form correctly it still doesn't work!
EDIT 2:
I created a 'form_invalid' function like this:
def form_invalid(self, form):
print(form.instance)
return super(UploadView, self).form_invalid()
which causes:
TypeError: form_invalid() missing 1 required positional argument: 'form'
This had me thinking as I am not receiving any errors when I get redirected back to the form after submitting. Here is the form I wrote: https://pastebin.com/3H6VRZR1
Also I tried testing it with just form.as_p
which causes the same problem
EDIT 3:
After testing some of the answers we found out that the form of the HTML page itself is probably the cause as the form arrived in form_invalid()
completely empty. I decided that I would try to use form.as_p
again see if it still caused the same issue as my custom form. Now I'm getting a new error:
null value in column "category_id" violates not-null constraint
DETAIL: Failing row contains (8, test new fom reg, test-new-fom-reg, null, test, test, 2018-01-10 13:44:58.81876+00, 2018-01-10 13:44:58.818789+00, 1, thumbnails/test-new-fom-reg.png, 2, 1, /home/trie/Desktop/django/vidmiotest/media/videos/test.mp4).
with:
USER
admin
GET
No GET data
POST
Variable Value
title 'test new fom reg'
category '8'
type '1'
time '1'
description 'test'
csrfmiddlewaretoken `BeizxWHU5KDbixit9vpxKoxEeBxgU9MNITaNlkM1qtI0Aq6kIThHrtjfUsQXjxON'
description_short 'test'
FILES
Variable Value
thumbnail <TemporaryUploadedFile: sixteentonineratio.png (image/jpeg)>
videoFile <TemporaryUploadedFile: test 3.mp4 (video/mp4)>
as the data the data send from the form which suggest (based on this) that category_id
is not in my model for the form. which it is (the field is just called category
), but why would it think it should be in there?
I just checked phppgadmin to see what the database looked like and there the field is called id_category
while in my model it's called category, why?
EDIT 4: I never added the Traceback for the error above:
Internal Server Error: /upload/ Traceback (most recent call last): File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) psycopg2.IntegrityError: null value in column "category_id" violates not-null constraint DETAIL: Failing row contains (12, test, test, null, test, test, 2018-01-16 18:18:25.907513+00, 2018-01-16 18:18:25.907538+00, 6, thumbnails/test_d1MHjMX.png, 2, 1, /home/trie/Desktop/django/vidmiotest/media/videos/test.mp4).
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 89, in dispatch
return handler(request, *args, **kwargs)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/views/generic/edit.py", line 142, in post
return self.form_valid(form)
File "/home/trie/Desktop/django/vidmiotest/upload/views.py", line 21, in form_valid
instance.save()
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 729, in save
force_update=force_update, update_fields=update_fields)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 759, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 842, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/base.py", line 880, in _do_insert
using=using, raw=raw)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/query.py", line 1125, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 1280, in execute_sql
cursor.execute(sql, params)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/home/trie/Desktop/django/venv/lib/python3.5/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/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/trie/Desktop/django/venv/lib/python3.5/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
django.db.utils.IntegrityError: null value in column "category_id" violates not-null constraint
DETAIL: Failing row contains (12, test, test, null, test, test, 2018-01-16 18:18:25.907513+00, 2018-01-16 18:18:25.907538+00, 6, thumbnails/test_d1MHjMX.png, 2, 1, /home/trie/Desktop/django/vidmiotest/media/videos/test.mp4).
The problem in the question is that super().form_valid() is called and overwriting the constructed form with context['form'] = VideoForm. Let the framework setup the form when using CreateView.
The inherited CreateView provides the functionality to setup the form, save the form, set self.object on the view, and redirect to a success url.
I.e CreateView.form_valid provides:
self.object = form.save()
The solution is correct to set the uploader in UploadView, but calling the super.form_valid will try to save the form again.
As I understand the desired behaviour is:
in code:
instance = form.save(commit=False)
instance.uploader = self.request.user
instance.save()
return redirect(self.get_success_url()) # Skip the call to super
Also as pointed out in other answer, the context['form'] = VideoForm will overwrite the form setup by the CreateView.
I suggest to look how the execution flow works for the CreateView, it will setup the form for the template context both in GET and POST situation.
One other way to solve it is to allow the VideoForm to accept uploader in init:
class VideoForm(forms.ModelForm):
def __init__(self, uploader, *args, **kwargs):
self.uploader = uploader
super().__init__(*args, **kwargs)
def save(self, commit=True):
instance = super().save(commit=False)
instance.uploader = self.uploader
if commit:
instance.save()
return instance
and provide the uploader to the form
class UploadView(..., CreateView):
def get_form_kwargs(self):
kwargs= super().get_form_kwargs()
kwargs['uploader'] = self.request.user
return kwargs
Hope it helps.
Looking at EDIT 3:
The reason it's say 'category_id' is that foreign keys in a django model will automatically get suffixed with '_id' as column name in the database. Documentation.
The Video model is likely to have a foreign key to Category.
If you find id_category in database, you might have gone out of sync with your migrations/models? You should probably try clear the database and/or to re-run makemigrations/migrate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With