django redirect after POST not working - django

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!

Related

Updating FileField in Django Form

Playing around with FileFiled and trying to update a form. I think my problem comes from the views.py.
I have a template where I can see a product, and I have the option to update the product by clicking on the update button.
When clicking on the update button, I am redirected to a form where I can update the product.
template
{% for TermsAndConditions in commercial_list %}
<a class="btn btn-outline-secondary" href="{% url 'update-commercial' TermsAndConditions.id %}">Update
</a>
{% endfor %}
templateform.py
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<h6>Upload terms</h6>
{{ form.attachment| as_crispy_field}}
{% if url %}
<p>Uploaded file {{url}}</p>
{%endif%}
<button type="submit" value="Submit" id="profile-btn" class="btn btn-primary custom-btn">Update</button>
</form>
My normal upload form (without FileField) looks like this:
views (without FileField)
def update_commercial(request, termsandconditions_id):
commercials = TermsAndConditions.objects.get(pk=termsandconditions_id)
form = TermsAndConditionsForm(request.POST or None, instance=commercials )
if form.is_valid():
form.save()
return redirect('list-commercial')
return render(request, 'main/update_commercial.html',{'form':form,'commercials':commercials})
With the addition of the FileField, I thought I would do something like this:
views (with FileField)
def update_commercial(request, termsandconditions_id):
commercials = TermsAndConditions.objects.get(pk=termsandconditions_id)
form = TermsAndConditionsForm(request.POST or None, request.FILES ,instance=commercials ) #the change being request.FILES
if form.is_valid():
form.save()
return redirect('list-commercial')
return render(request, 'main/update_commercial.html',{'form':form,'commercials':commercials})
Problem is, when I do that the update button in the template becomes invalid (it doesn't redirect to the update form).
I think my problem is how to handle the or None and request.FILES together. I tried different combinations but none have worked. Hoping someone might be able to shed some light.
(I have add the models and url files, as I dont think these are the problem and didnt want to make this post longer than it should be, but feel free to let me know)
Ok, figured it out in the end.
Posting the answer just in case for anyone who needs it.
I needed to repeat or None for request.FILES.
def update_commercial(request, termsandconditions_id):
commercials = TermsAndConditions.objects.get(pk=termsandconditions_id)
form = TermsAndConditionsForm(request.POST or None, request.FILES or None,instance=commercials )
if form.is_valid():
form.save()
return redirect('list-commercial')
return render(request, 'main/update_commercial.html',{'form':form,'commercials':commercials})

WTF form.validate_on_submit() not working

I have the following code and I'm submitting a form. When I hit the submit button, my form validation prints out False. I've checked and made sure I'm including everything from different posts, but I can't get it to validate. Is there anything I'm doing wrong?
#app.route('/index.html', methods=['GET', 'POST'])
def index():
user = {'nickname': 'Rafa'}
form = FilterForm()
print("about to validate", file=sys.stderr)
if form.validate_on_submit():
print("validated", file=sys.stderr)
filters_array = form.filter.split(',')
streaming(filters_array)
response = {"response", "yes"}
redirect("/authenticate")
return render_template('index.html',
title="Home",
user=user,
form=form)
class FilterForm(Form):
filter = StringField('filter', validators=[DataRequired()])
Here is my Jinja file
{% block content %}
<h1> I have successfully navigated to the title pagee </h1>
<h1> Hello, {{user.nickname}}!</h1>
<h1> Get Tweets </h1>
<p> Please enter a comma delimited list of filters</p>
<form action="" method="post" name="login">
{{form.filter(size=80)}}
<input type="submit" value="Get Tweets!">
</form>
{% endblock %}
FilterForm should not be indented at the same level as def index(). More importantly, you don't have a csrf_token in your form. Which will prevent it from validating.
Add this to your form:
{{ form.csrf_token }}
Lastly, when validating with wtforms, the errors are populated in the form object. So after an if validate, try printing form.errors and you'll find out exactly what is wrong.
Another requirement is that when you use form.validate_on_submit, you have to make sure that you had use all fields of your form model.
I have found some syntax error in your code, maybe that will cause the problem you have met.
first, the problem in your decorator app.route:
app.route('/index')
second, in your html file:
form action='/index'

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

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()

Django modelformset_factory invalid, return request.POST data to forms

I want to return the data that has been entered back in place in the form using django modelformset_factory
view
from django.forms.models import modelformset_factory
ArticleFormSet = modelformset_factory(Article, extra=2)
formset = ArticleFormSet(queryset=Article.objects.none())
if request.POST:
formset = ArticleFormSet(request.POST)
if formset.is_valid():
instances = formset.save(commit=False)
formset = ArticleFormSet(queryset=instances)
else:
## ?? RETURN formset with request.POST data in form ??
pass
template
<form method="POST" id="articleForm" action=".">{% csrf_token %}
{% for form in forms %}
{{form.as_p}}
{% endfor %}
</form>
Using Django 1.4 I'm getting:
Validation Error: No exception supplied
Have tried a range for variations on initial=request.POST, but no joy.
Any advice is appreciated thank you!
You don't need to do anything. Your formset is already populated with the POST data. Just pass that to the template. The usual way to do this is not to have an else clause, but just fall through to the same render call that displayed the forms in the first place.
Checked to see if the "management form" details were not being automatically passed, turns out they weren't (per here: https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform).
Cobbling this "Management Form data" on to request.POST seems to have resolved the otherwise mysterious validation error. I wonder if this a genuine 1.4 bug?
if request.POST:
forms_mgmt = {'form-TOTAL_FORMS': u'2', 'form-INITIAL_FORMS': u'0', 'form-MAX_NUM_FORMS': u''}
data_dict = dict(request.POST.items() + forms_mgmt.items())
formset = ArticleFormSet(data_dict)
if formset.is_valid():
instances = formset.save(commit=False)
formset = ArticleFormSet(queryset=instances)
Thanks to #Daniel Roseman for helping me not go down the wrong path.
Further to #Williams answer, reading through https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform you can find that the management form data that can be rendered into the template with {{ my_formset.management_form }}:
<form method="POST" id="articleForm" action=".">{% csrf_token %}
{% for form in forms %}
{{form.as_p}}
{% endfor %}
{{ my_formset.management_form }}
</form>
Then, once the form has been posted you can use:
formset = ArticleFormSet(request.POST)

Django form validation with GET

I have a form which allows users to select several parameters to allow faceted querying of data. As there is no data entry going on here I want the form to post to GET and I have a another view with a different template which displays the results.
I want the form to validate as normal so that if a required field is not completed the corresponding errors are displayed. At the moment my process looks like this (simplified):
my search view:
def search(request):
...
context['form'] = GraphForm()
...
return render(request, 'search.html', context)
my results view:
def results(request):
if 'submit' in request.GET:
# process GET variables as query
...
return render(request, 'results.html', context)
my search.html template:
<form action="{% url results %}" method="get">{% csrf_token %}
{% for field in form %}
<div class="field_wrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<input type="submit" name="submit" value="Query" />
</form>
Given that the form submits to another url with separate view code, what is the best way to go about validating (highlighting errors), and ensuring I have my GET data?
Any help much appreciated.
This might be a little late, but I think the following will work while maintaining similarity to 'POST' workflow:
Instead of having two different views for searching and displaying results, just have one view. The normal codepath described for post forms can then be followed. Instead of using request.method == 'POST' to detect form submission, we instead use 'submit' in request.GET. If using javascript to submit the form, make sure that 'submit' is included in the GET data or use a hidden field to detect form submission.
views.py
def search(request):
context_dict = {}
if 'submit' in request.GET:
form = GraphForm(request.GET)
if form.is_valid():
#do search and add results to context
#If you don't want to use a single view,
# you would redirect to results view here.
results = get_results(**form.cleaned_date)
context_dict['results'] = results
else:
form = GraphForm()
context_dict['form'] = form
return render(request, 'search.html', context_dict)
search.html
<form action="{% url 'search' %}" method="get">
{{form}}
<input type="submit" name="submit" value="Query" />
</form>
{% if results %}
{% include 'results.html' %}
{% endif %}
You should be able to pass request.GET just like request.POST to the form. The form simply accepts a data dictionary. It doesn't care where that comes from. Have you already tried that?
Use JavaScript/jQuery for form validation. All you need to do is add an id to form, and in the corresponding Javascript, do something like
document.getElementById("#form").onsubmit = checkForm();
or using jQuery
$("#form").submit(checkForm);
where checkForm() returns true upon successful validation, and false otherwise. (Note that, if you do not return false, form submission will continue as usual.)
Which fields you check for/validate can also change by using Django's templates.