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:
set uploader
save the object
redirect to success url
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
You certainly don't need that context['form'] = VideoForm line. Apart from anything else, it's overwriting the existing form so that your template will never see any errors.
I am getting the follwing error message the I try to open the url:
Request Method: GET
Request URL: http://localhost:8000/core/jmc/material/generate
Django Version: 1.8
Exception Type: AttributeError
Exception Value: 'bool' object has no attribute 'user'
Exception Location: /usr/local/lib/python2.7/dist-packages/django/contrib/auth/decorators.py in _wrapped_view, line 21
Also the traceback looks like this:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/decorators.py" in _wrapped_view
22. return view_func(request, *args, **kwargs)
File "/home/dev/Documents/Program Codes/Python/Django/Zeus2/core/project/jmc.py" in jmc_material_generator
168. jmc_material_generator(False)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/decorators.py" in _wrapped_view
21. if test_func(request.user):
My view is as follows:
#login_required(login_url='login')
def jmc_material_generator(request):
# Permission level check
if request.user.groups.all()[0].name not in ['Super-Admin', 'Admin']:
return redirect('index')
with transaction.atomic():
jmc_material_generator(False)
return redirect('index')
Your view function name is the same as the function being called on line 8 (jmc_material_generator(False)). This in turn is calling your view function again and passing in a boolean instead of a request object. You need to either rename your view function or rename the jmc_material_generator(False) import when you import it into the view.py file.
# you can do import x as X which renamed the imported function
from ... import jmc_material_generator as jmc_generator
#login_required(login_url='login')
def jmc_material_generator(request):
# Permission level check
if request.user.groups.all()[0].name not in ['Super-Admin', 'Admin']:
return redirect('index')
with transaction.atomic():
jmc_generator(False) # notice the rename of this function
return redirect('index')
I'm writing a basic RSS feed reader in Django. I have a form in which a user submits a rss feed, and I add it to his feeds list. But for some reason, I'm unable to extract basic information about the feed using feed parser.
when i run the following code:
def form_valid(self, form):
user = self.request.user
link = form.cleaned_data['link']
feed = feedparser.parse(link).feed
title = feed.title
try:
feed_obj = Feed.objects.get(link=link)
except ObjectDoesNotExist:
feed_obj = Feed(link=link, title=title)
feed_obj.save()
user.get_profile().feeds.add(feed_obj)
return super(DashboardView, self).form_valid(form)
Django throws me an "object has no attribute 'title'" exception on line 5:
title = feed.title
Full error details are:
Traceback:
File "/home/yaniv/nextfeed/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
115. response = callback(request, *callback_args, **callback_kwargs)
File "/home/yaniv/nextfeed/venv/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
25. return view_func(request, *args, **kwargs)
File "/home/yaniv/nextfeed/venv/local/lib/python2.7/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/home/yaniv/nextfeed/venv/local/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
86. return handler(request, *args, **kwargs)
File "/home/yaniv/nextfeed/venv/local/lib/python2.7/site-packages/django/views/generic/edit.py" in post
165. return self.form_valid(form)
File "/home/yaniv/nextfeed/profiles/views.py" in form_valid
48. title = feed.title
File "/home/yaniv/nextfeed/venv/local/lib/python2.7/site-packages/feedparser.py" in __getattr__
416. raise AttributeError, "object has no attribute '%s'" % key
Exception Type: AttributeError at /dashboard
Exception Value: object has no attribute 'title'
What am I doing wrong?
EDIT: I traced the program with pdb. Right before the problematic line, I got:
(Pdb) link
u'http://feedparser.org/docs/examples/rss20.xml'
(Pdb) feed
{'xhtml_script': {'type': u'text/javascript', 'language': u'javascript'}, 'summary': u''}
It's been a while since I used feedparser, but IIRC, the parser returns a dictionary, like so:
foo = feedparser.parse(link)
feed = foo['feed']
title = feed['title']
You seem to have gotten an object back from foo.feed, but that's not what you want.
When I try to do request.user.is_authenticated() I get a ValidationError: None is not a valid ObjectId
I'm trying to track down the problem but I do not what's causing it.I'm using MongoEngine (and MongoDB.)
I have the following in my settings.py:
AUTHENTICATION_BACKENDS = (
'mongoengine.django.auth.MongoEngineBackend',
'rs.claimutil.auth_backend.ClaimAuthBackend',
)
SESSION_ENGINE = 'mongoengine.django.sessions'
This is what I get:
Traceback: File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/handlers/base.py"
in get_response
111. response = callback(request, *callback_args, **callback_kwargs) File "/Users/bastiano/Documents/ttsf/rsrv/views.py" in reserve
11. if not request.user.is_authenticated(): File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/utils/functional.py"
in inner
184. self._setup() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/utils/functional.py"
in _setup
248. self._wrapped = self._setupfunc() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/auth/middleware.py"
in
16. request.user = SimpleLazyObject(lambda: get_user(request)) File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/auth/middleware.py"
in get_user
8. request._cached_user = auth.get_user(request) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/contrib/auth/init.py"
in get_user
101. user = backend.get_user(user_id) or AnonymousUser() File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/django/auth.py"
in get_user
149. return User.objects.with_id(user_id) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in with_id
923. return self.filter(pk=object_id).first() File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in first
843. result = self[0] File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in getitem
1136. return self._document._from_son(self._cursor[key]) File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in _cursor
579. self._cursor_obj = self._collection.find(self._query, File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in _query
375. self._mongo_query = self._query_obj.to_query(self._document) File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in to_query
202. query = query.accept(QueryCompilerVisitor(document)) File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in accept
267. return visitor.visit_query(self) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in visit_query
159. return QuerySet._transform_query(self.document, **query.query) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/queryset.py"
in _transform_query
720. value = field.prepare_query_value(op, value) File
"/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/base.py"
in prepare_query_value
455. return self.to_mongo(value) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/base.py"
in to_mongo
451. self.error(unicode(e)) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mongoengine/base.py"
in error
203. raise ValidationError(message, errors=errors, field_name=field_name)
Exception Type: ValidationError at /rs/claim Exception Value: None is
not a valid ObjectId
Any ideas why this is happening? Is there an easier way to do user authentication in Django + MongoDB?
Views.py:
def claim(request):
if request.method == 'GET':
if not request.user.is_authenticated():
return shortcuts.redirect('rs/login')
all_b = dbutil.get_b(all=True)
return shortcuts.render_to_response('rs/index.html',
{'all_b':all_b},
context_instance=template.RequestContext(request))
elif request.method == 'POST':
The rest of the view is omitted for simplicity. I used ipdb to debug it and if not request.user.is_authenticated() is the problem. I tried using django.contrib.auth.decorators.login_required.decorator before, but it, too, failed.
Try to update your mongoengine to the latest version. In master, it is
def get_user(userid):
"""Returns a User object from an id (User.id). Django's equivalent takes
request, but taking an id instead leaves it up to the developer to store
the id in any way they want (session, signed cookie, etc.)
"""
# your installed mongoengine might not include following two lines
if not userid:
return AnonymousUser()
return MongoEngineBackend().get_user(userid) or AnonymousUser()
A userid w/ value of None causes the problem, according to the trackback.
What version of MongoEngine / Django are you using?
Have you enabled the django.contrib.auth.middleware.AuthenticationMiddleware? That should set a User instance or AnonymousUser to the request.
What does rs.claimutil.auth_backend.ClaimAuthBackend look like? And what does its get_user method return? Does it stop erroring if you just have one authentication backend?
In one of my views I had the following:
r_v.obj.backend = 'mongoengine.django.auth.MongoEngineBackend', which is why Django was ignoring the AUTHENTICATION_BACKENDS in settings.py, and was never using my custom authentication backend.
I'm trying to validate a form containing a ModelChoiceField:
forms.py:
from django import forms
from modelchoicetest.models import SomeObject
class SomeObjectAddForm(forms.ModelForm):
class Meta:
model = SomeObject
models.py:
from django.db import models
class SomeChoice(models.Model):
name = models.CharField(max_length=16)
def __unicode__(self):
return self.name
class SomeObject(models.Model):
choice = models.ForeignKey(SomeChoice)
views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from forms import SomeObjectAddForm
def add(request):
if request.method == 'POST':
form = SomeObjectAddForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('modelchoicetest_add'))
else:
form = SomeObjectAddForm()
return render_to_response('modelchoicetest/index.html',
{'form': form},
context_instance=RequestContext(request))
When it is used in normal circumstances, everything goes just fine. But I'd like to protect the form from the invalid input. It's pretty obvious that I must get forms.ValidationError when I put invalid value in this field, isn't it? But if I try to submit a form with a value 'invalid' in 'somechoice' field, I get
ValueError: invalid literal for int() with base 10: 'invalid'
and not the expected forms.ValidationError. What should I do? I tried to place a def clean_somechoice(self) to check this field but that didn't work: ValueError happens before it comes to clean_somechoice()
Plus I don't think this is a good solution, there must be something more simple but I just missed that.
here's the full traceback:
Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
101. response = callback(request, *callback_args, **callback_kwargs)
File "/home/andrey/public_html/example/modelchoicetest/views.py" in add
11. if form.is_valid():
File "/usr/local/lib/python2.6/dist-packages/django/forms/forms.py" in is_valid
120. return self.is_bound and not bool(self.errors)
File "/usr/local/lib/python2.6/dist-packages/django/forms/forms.py" in _get_errors
111. self.full_clean()
File "/usr/local/lib/python2.6/dist-packages/django/forms/forms.py" in full_clean
276. value = field.clean(value)
File "/usr/local/lib/python2.6/dist-packages/django/forms/fields.py" in clean
154. value = self.to_python(value)
File "/usr/local/lib/python2.6/dist-packages/django/forms/models.py" in to_python
911. value = self.queryset.get(**{key: value})
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in get
330. clone = self.filter(*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in filter
536. return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in _filter_or_exclude
554. clone.query.add_q(Q(*args, **kwargs))
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py" in add_q
1109. can_reuse=used_aliases)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py" in add_filter
1048. connector)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/where.py" in add
66. value = obj.prepare(lookup_type, value)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/where.py" in prepare
267. return self.field.get_prep_lookup(lookup_type, value)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/__init__.py" in get_prep_lookup
314. return self.get_prep_value(value)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/fields/__init__.py" in get_prep_value
496. return int(value)
Exception Type: ValueError at /
Exception Value: invalid literal for int() with base 10: 'invalid'
It looks to me like the exception is being raised by the clean method of the actual ModelChoiceField object. Because it's a foreign key, Django is expecting an int, which would be representative of the pk for SomeChoice. How exactly are you passing invalid into the form?
RESPONSE TO COMMENT
If you really feel you need to catch this, you can try overriding the default ModelChoiceField by creating a new field called choice and pass in the to_field_name kwarg into the ModelChoiceField __init__ method. This way Django won't be filtering on pk, and won't raise that exception.
Personally I wouldn't use this solution. There is no need to accommodate user who are hacking your form.
This is known Django bug:
http://code.djangoproject.com/ticket/11716
And while this bug is not fixed, you can only handle ValueError manually.