Django - AttributeError => 'set' object has no attribute 'get' - django

I'm going through the book Django 1.0 Website Development where you build a small social bookmarking application. I'm at chapter 5 where you create a form to add bookmarks and although I've followed the instructions and have been struggling on this error for days. I get the error:
AttributeError at /save/
'set' object has no attribute 'get'
The error is being thrown on line 6 of the template {{ form.as_p }}
The views.py code is:
def bookmark_save_page(request):
if request.method == 'POST':
form = BookmarkSaveForm(request)
if form.is_valid():
# create or get link.
link, dummy = Link.objects.get_or_create(
url=form.cleaned_data['url']
)
# create or get bookmark.
bookmark, created = Bookmark.objects.get_or_create(
user=request.user,
link=link
)
# if bookmark is being updated, clear the old tag list
if not created:
bookmark.tag_set.clear()
# create new tag list
tag_names = form.cleaned_data['tags'].split()
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add()
# save bookmark to database
bookmark.save()
return HttpResponseRedirect(
'/user/%s/' % request.user.username
)
else:
form = BookmarkSaveForm()
variables = RequestContext(request, {
'form' : form
})
return render_to_response('bookmark_save.html', variables)
And the template code is:
{% extends "base.html" %}
{% block title %}Save Bookmark{% endblock %}
{% block head %}Save Bookmark{% endblock %}
{% block content %}
<form method="post" action=".">{% csrf_token %}
**{{ form.as_p }}**
<input type="submit" value="save" />
</form>
{% endblock %}
Any help would be much appreciated as I'm stuck at this point in the book and can't seem to find an answer. Thanks!

Is this an error for you?
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add() # not adding the tag?
Shouldn't it be: bookmark.tag_set.add(tag) ? The .add() doesn't actually cause an error, but I know you aren't adding your tag.
Without seeing the traceback, I'm guessing.
My other guess is that you might be using the RequestContext wrong?
return render_to_response('bookmark_save.html',
{'form': form},
context_instance=RequestContext(request))
I believe the way you are using it now is meant for the non-shortcut approach of using an HttpResponse()

Related

Queryset object in Django form not iterable

I'm trying to get the form to create the fields based on what exam page the user is on. In the error page, all local variables have the correct value for form and view, but I keep getting ExamQuestion object not iterable and an error at line 0 of the template. It also highlights the render() at line 44 in the view as the source of the problem. If I change line 28 from exam__name=exam_name to exam__name="exam_name", basically turning the variable into a str, the page runs but no data is passed.
In the error console choice_list shows querysets as individual list items as it should for forms.py
How do I make the object ExamQuestion iterable? I've been stumped for a week now. I've written a hundred ways at this point.
I know it's listing questions instead of answers for the questions, I'm just trying to get it to load ANY queryset and freaking run at this point.
view
def exampage(request, exam_name):
exams = Exam.objects.all()
questionlist = ExamQuestion.objects.filter(exam__name=exam_name)
choicelist = ExamChoice.objects.filter(question__exam__name=exam_name)
form = ExamTest(request.POST, exam_name=exam_name)
if request.method == "POST":
if form.is_valid():
#form.save()
#choice = form.cleaned_data.get('choice')
return redirect('exampage.html')
return render(request, 'exams/exampage.html', {'exams': exams,'questionlist': questionlist, 'exam_name': exam_name, 'choicelist': choicelist, 'form': form, 'choice': choice})
else:
form = ExamTest(exam_name=exam_name)
return render(request, 'exams/exampage.html', {'exams': exams,'questionlist': questionlist, 'exam_name': exam_name, 'choicelist': choicelist, 'form': form})
form
class ExamTest(forms.Form):
def __init__(self, *args, **kwargs):
exam_name = kwargs.pop('exam_name')
super(ExamTest, self).__init__(*args, **kwargs)
#choice_list = [x for x in ExamQuestion.objects.filter(exam__name="dcjs01")]
#choice_list = []
x = ExamQuestion.objects.filter(exam__name=exam_name)
#for q in x:
# choice_list.append(q)
self.fields["choices"] = forms.ChoiceField(choices=x, label="testlabel")
template
{% extends 'portal/base.html' %}
{% block content %}
<h1>{{ exam_name }} Page</h1>
{{ exam_id }}
<hr>
{% for exam in exams %}
<li>{{ exam }}</li>
{% endfor %}
<h1>! {{ questionlist }} !</h1>
<form method="post" action="#">
{% csrf_token %}
formtest{{ form }}
<button type="submit"> finish test </button>
</form>
{% endblock %}
The first part of the question is - you getting the ExamQuestion not iterable error:
here I think is the problem, that you, in the Form init function pass the Queryset (objects.filter(xxx)), but not the .all() which will select it.
the second thought is - would'n it be better to pass the questions as a parameter to the Form, as you previously selected all the question for this particular exam?
figured it out. choices=x needs to be a tuple
self.fields['name'] = forms.ChoiceField(choices=tuple([(name, name) for name in x]))

Using redirect sends me to /tag/?search=input instead of /tag/input (Django URL argument from form)

I have a page where there is a path /tag/name_of_tag and you can see all posts tagged with that tag.
Inside the page, you can also select another tag in a form and go to that tag.
The problem is that instead of going to /tag/searched_tag, it goes to /tag/?search=searched_tag
How can I change it doesn't leave the ?search= part?
urls.py:
url(r'tag/(?P<input_tag>\w+)$', views.tag_view, name='tag'),
views.py:
def tag_view(request, input_tag):
form = TagSearchForm()
if request.method == 'GET':
form = TagSearchForm(request.GET)
if form.is_valid():
input = form.cleaned_data['search']
print(input)
return redirect('fortykwords:tag_view', input)
else:
form = SearchForm()
latest_post_list = Post.objects.filter(tags=input_tag, status__exact="published")
paginator = Paginator(latest_post_list, 3)
page = request.GET.get('page')
posts = paginator.get_page(page)
context = {'latest_post_list': latest_post_list, 'page_tag': input_tag, 'form': form}
return render(request, 'fortykwords/tag.html', context)
forms.py:
class TagSearchForm(forms.Form):
search = tagulous.forms.SingleTagField(
tag_options=tagulous.models.TagOptions(
autocomplete_view='fortykwords:post_tags_autocomplete'
),
label='Tags',
required=True,
help_text=_('Filter by lead tags. You can organize leads by any tag you want.'),
)
tag.html:
{% extends "base_generic.html" %}
{% block content %}
<form action="." method="get">
{{ form }}
<input type="submit" value="Submit" />
</form>
<h3>Posts with the tag {{ page_tag }}</h3>
{% if latest_post_list %}
<ul>
{% for post in latest_post_list %}
<li> {{ post.author }} {{ post.pub_date }}
<br>
{{ post.title }}</li>
{% for tag in post.tags.all %}
{{ tag.name }}
{% endfor %}
{% endfor %}
</ul>
{% else %}
<p>No posts are available.</p>
{% endif %}
{% endblock %}
You need to provide the argument input to redirect method as input_tag=input.
Example:
return redirect('fortykwords:tag_view', input_tag=input)
It's showing as /tag/?search=searched_tag because your form is submitting by GET but never getting to the redirect. It seems is_valid() is returning False.
I've tested a very similar version of your code and don't think it's a bug in tagulous, but would still be interested to know what had gone wrong (I wrote tagulous). Spotted a couple of places you can streamline your code a bit, so try::
def tag_view(request, input_tag):
# Can't see any POSTs in your example, so you can pass the form GET here
# Might also be nice to pass the original tag in so it shows in the form
form = TagSearchForm(request.GET, initial={'search': input_tag})
# The form already has the GET, so you can go straight into the is_valid
if form.is_valid():
input = form.cleaned_data['search']
print('Valid: ', input)
return redirect('fortykwords:tag_view', input)
else:
print('Invalid: ', form.errors, form.non_field_errors)
# You can remove the else for if not GET, which would never be reached
# on to pagination as before
(although fwiw I'd recommend ipdb instead of print)

django redirect after POST not working

I have apparently forgotten something really basic about django. Here's my views.py:
def sourcedoc_create(request):
if request.method == 'POST': # If the form has been submitted...
form = SourcedocForm(request.POST, request.FILES) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
handle_uploaded_file(request.FILES['doc'])
form.save()
return HttpResponseRedirect('/index/') # Redirect after POST
else:
form = SourcedocForm() # An unbound form
return render_to_response(
'sourcedoc_create.html',
{'form': form},
RequestContext(request)
Here's the relevant part of urls.py:
url(r'^$', index),
url(r'^index/', index),
url(r'^sourcedoc/create/', sourcedoc_create),
When I run the app, I create the record in the database, and the uploaded file appears successfully in the relevant directory (thus I infer that the form.save worked ok), but then I get:
KeyError at /sourcedoc/create/
0
Request Method: POST
Request URL: http://www.rosshartshorn.net/worldmaker/sourcedoc/create/
Django Version: 1.4.3
It appears that my HttpResponseRedirect is, for whatever reason, not working, and it's trying to re-POST and throwing a KeyError off a blank form? Or something. In any event, it's not redirecting. When I manually go to /index/, all is well, and the new record is there.
Any ideas what is wrong with my redirect?
In case the forms are relevant:
<body>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>New Post</h1>
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</form>
Also, I'm using mongoforms, which is supposed to work like ModelForms:
from mongodbforms import DocumentForm
class SourcedocForm(DocumentForm):
class Meta:
document = Sourcedoc
It seems to have been at least somewhat related to this post: Django MongodbForms KeyError _meta['cascade'].
So, I just upgraded to Django 1.5 and the newest mongodbforms. This eliminated that error, although I was then getting a problem similar to this:
MongoKit "ImportError: No module named objectid " error
I just implemented keppla's answer from that second post, and it now seems to work!

Retrieving image in django, update/replace image in django

Hi I have saved an image using my django project with the help of models
as
Image = models.ImageField(upload_to="images/profileimages/")
name = models.CharFiled(max_length=20)
#rest of the fileds.
Once I have saved this information I want to change/update it. For this i have used a view as
def Information_change(request):
instance = get_object_or_404(information,pk=request.user.id)
if request.method == 'POST':
iform = informationForm(instance=instance, data=request.POST, files=request.FILES)
if iform.is_valid():
instance = iform.save()
return HttpResponseRedirect('/')
else:
iform = informationForm(instance=instance)
return render_to_response('registration/information_change.html',{'iform':iform}, RequestContext(request))
In my templates am getting all the information in realated fields like name fields contains my name and all the charfields are showing the information, but the image fileds did not show the image/path or any other thing. Rest of the fields can be changed and i am able to edit my name fileds but unable to replace/change the image using this code. how can I fix this. Any help would be greatly appreciated.
My .html file contains
{% block content %}
{% if iform.errors %}
<p style="color: red;">
Please correct the error{{ iform.errors|pluralize }} below.
</p>
{% endif %}
<form method="post" action=".", enctype="multipart/form-data>
{{ iform.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
First of all do what #Rohan has suggested you. In your view you have a bug, what if there was a case when your form is not valid? Then your view will not return an HTTP response because you have not handled that. Just remove the else of if request.Method == 'POST' and indent back following two lines:
iform = informationForm(instance=instance)
return render_to_response('registration/information_change.html',{'iform':iform}, RequestContext(request))
This will fix the bug which I mention. May be that will show some form errors which is related to image field.
I see 2 issues in your form tag:
comma ',' after actions attribute
No closing quote for enctype attribute value

Displaying None Field Errors in Django Template

I want to display my non_field_erors in my template. So far, I can display all kind of errors of my forms with:
-> base.html
{% if form.errors %}
{% for field in form %}
{% if field.errors %}
<div class="ui-state-error ui-corner-all notification" >
<p>
<span class="ui-icon ui-icon-alert"></span>
{{ field.label_tag }}:{{ field.errors|striptags }}
<a class="hide" onClick="hideBar(this)">hide</a>
</p>
</div>
{% endif %}
{% endfor%}
{% endif %}
AND
{{ form.non_field_errors }}
I've added a new form which has only an IntegerField:
class MerchantForm(forms.ModelForm):
price = forms.IntegerField(widget=forms.TextInput(attrs={'class':'small'}))
def clean_price(self):
price = self.cleaned_data.get('price')
if price == 120:
raise forms.ValidationError('error blah.')
return price
When I post price as 120, I don't get any validation errors in my page.
And my view is:
def bid(request,product_slug):
.
.
form = MerchantForm()
context = RequestContext(request,{
'form':form,
....
})
if request.method == 'POST':
form = MerchantForm(request.POST)
if form.is_valid():
return HttpResponse('ok')
# else:
# return HttpResponse(form.errors.get('__all__'))
return render_to_response('bid.html',context_instance=context)
I can retrieve the error with commented lines but I don't want to do that in views.py. Any ideas ?
Oh dear.
First of all, why are you asking about non_field_errors when the code snippet you post clearly has the error as being raised in clean_price, and therefore is associated with ths price field?
Secondly, your view code is upside down. You create an empty form instance, and add it to the context. Then you create another form instance, bound to the POST data, but don't put it into the context. So the template never sees the bound form, so naturally you never see any validation errors in the template.