#Contact.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class='row'>
<div class ='col-md-4 col-md-offset-4'>
<h1> {{title}} </h1>
{% if confirm_message %}
<p>{{ confirm_message }}</p>
{% endif %}
{% if form %}
<form method='POST' action=''>
{% csrf_token %}
{{ form.errors }}
{{ form.non_field_errors }}
{% crispy form %}
<input type='submit' value='submit form' class='btn btn-default' />
</form>
{% endif %}
</div>
</div>
{% endblock %}
# froms.py
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Field
from crispy_forms.bootstrap import (PrependedText, PrependedAppendedText, FormActions)
class contactForm(forms.Form):
name = forms.CharField(required = False , max_length =100, help_text="100 characters max ")
email= forms.EmailField(required = True)
comment = forms.CharField(required =True, widget=forms.Textarea)
Server Logs
System check identified no issues (0 silenced).
September 13, 2017 - 07:38:19
Django version 1.11.5, using settings 'app3.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
GET
hello from not valid
[13/Sep/2017 07:38:23] "GET /contact/ HTTP/1.1" 200 5413
[13/Sep/2017 07:42:20] "GET / HTTP/1.1" 200 4356
[13/Sep/2017 07:42:27] "GET /about/ HTTP/1.1" 200 3985
GET
hello from not valid
[13/Sep/2017 07:42:37] "GET /contact/ HTTP/1.1" 200 5413
The request never becomes post. When I hit submit on the form it
never shows up as post request. What could possibly I be doing wrong ?
#Views page
from django.shortcuts import render
from .forms import contactForm
from django.conf import settings
from django.core.mail import send_mail
def contact(request):
form = contactForm()
confirm_message = None
title = 'Contact'
context ={'title' : title, 'form' : form }
print request.method
# print form
# if request.method=='GET':
# form = contactForm()
if request.method =='POST':
form = contactForm(request.POST )
print "hello from not valid "
if form.is_valid():
print "hello"
name = form.cleaned_data['name']
comment=form.cleaned_data['comment']
emailFrom=form.cleaned_data['email']
subject ='Message from mysite.com'
message='%s %s' %(comment, name )
emailTo=[settings.EMAIL_HOST_USER]
title = 'Thank you'
confirm_message="Thank you, we ll get back to you "
context ={'title' : title,'confirm_message' :
confirm_message}
template ='contact.html'
return render(request , template , context)
This is my views page handling all the business logic for the application
When I run this application, the code never reaches the request==post block. I am unable to figure out why ? I pasted contact.html and forms.py for more visibility.
EDIT:
I have implemented all the changes suggested but the form never renders the post method. I could say something wrong with form but I don't know what.
UPDATE2:
The issue has been resolved and the problem seems to crispy forms. I read the documentation and couldn't find anything to pin point the error besides the fact that it was rendering the request as post. Decided to remove it and now it works perfectly fine.
Thank you all for your help and suggestions.
You can see "hello from not valid" string in your server log that means your POST request is successfully sended to server.
However, second if statement checks if form is valid and this is the line where things get south. Since you do not have else case for not valid form, you cannot see the right error message.
Fix your form and cover the not valid case.
In your template your form is constructed wrongly.
If you use {% crispy %} tag in your template, it makes a form.
If you don't want form tags included, set the form_tag attribute for your form helper to False.
self.helper.form_tag = False
You need not explicitly use {% csrftoken %} tag, crispy adds that for you.
Also I don't see that you're using crispy form helper in your forms.py.
Related
Sure I've missed something obvious, but any help appreciated.
I have a form model:
class UserForm(forms.Form):
name = forms.CharField()
A view:
def userform(req):
context = {}
context['user_form'] = UserForm()
context['message'] = 'test message'
return render(req, 'apps/userform.html', context)
And a template:
{% extends 'base.html' %}
{% block title %} | User Form {% endblock %}
{% block content %}
<h1>Form page</h1>
<form method='POST'>
{% csrf_token %}
{{ user_form }}
<button type='submit'>Send</button>
</form>
{{ message }}
{% endblock %}
I'm pretty sure everything is connected correctly and imported as required - the 'message' property on context renders fine under the form.
However, {{ user_form }} in the template renders the actual Form object instance, rather than the actual form field I'm expecting. I see:
<userform.views.UserForm object at 0x7fcab17e5c10>
Then the form submit button.
What have I missed?
Django 4, if that matters.
So the issue was I had a class based view in the views file with the same name as my Form class - I guess that was getting instantiated, rather than the Form class. Commented out the CBV and everything worked.
If I'd looked harder at the error message, I would have probably seen this sooner as the instantiated object is clearly in the views folder, rather than the forms one...
new to Django and I'm having a little trouble with this.
I have a registration form that creates rows in a database on successful submission.
Upon submission, I would like to redirect the user to a login form (which requires me to pass in the form as a parameter for render()), passing a status of 'REGISTRATION_SUCCESSFUL' as a parameter as well.
return render(request, 'login.html', {
'form': login_form(),
'status': 'REGISTRATION_SUCCESSFUL'
})
Based on the status, my template then displays a message to indicate the successful registration.
All works fine until you try to refresh the login page, it tries to submit the registration form again (I suppose because the request was forwarded to the login page).
Everything I've tried involves forwarding the request, which is proving to be a problem. Help?
Thanks in advance!
After form submission instead of using render, use HTTPResponseRedirect. Always return an HttpResponseRedirect after successfully dealing with POST data. This prevents data from being posted twice if a user hits the Back button.
The problem that you face here is that HTTPResponseRedirect does not allow you to pass the context of the status being REGISTRATION_SUCCESSFUL.
Based on the status, my template then displays a message to indicate the successful registration.
This is where you could use Django's messages framework. Right before the HTTPResponseRedirect, you could do something like:
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import RegistrationForm
def registration(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# ... do something special here if needed
messages.add_message(request, messages.INFO, 'Registration was successful!')
return HttpResponseRedirect(reverse('login_page'))
else:
form = RegistrationForm()
return render(request, 'registration.html', {'form': form})
Now in your "login_page", you can show the messages. FYI - the messages are on a per-session basis, so the "Registration was successful" message will only be displayed to the user you redirected:
login_page.html: (example from the messages documentation)
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }} </li>
{% endfor %}
</ul>
{% endif %}
<form method="post">{% csrf_token %}
{{ form }} {# Your login form #}
</form>
In this example, any messages you added will be displayed above your login form. If there are other messages such as "invalid registration," they will be displayed.
Please be sure to Enable the Django Messages Framework by adding the following to your settings.INSTALLED_APPS:
INSTALLED_APPS = (
...
'django.contrib.messages',
)
And your settings.MIDDLEWARE_CLASSES must contain:
MIDDLEWARE_CLASSES = (
...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
And your settings.TEMPLATE_CONTEXT_PROCESSORS must contain:
TEMPLATE_CONTEXT_PROCESSORS = (
...
'django.contrib.messages.context_processors.messages',
)
After registration is successful, you might have to consider redirect which is a common practice after a successful post is done.
Django provides a short-cut for redirects.
return redirect('some-view-name', foo='bar')
return redirect('/some/url/')
For your case you can consider:
kwargs={'status': 'REGISTRATION_SUCCESSFUL' }
return redirect('login-view', **kwargs)
from django.contrib import messages
from django.http import HttpResponseRedirect
if form1.is_valid():
registration = form1.save(commit=False)
registration.save()
messages.success(request, 'Your message here.')
return HttpResponseRedirect('/login/')
in templates.
in div where you want to display the message
{% block message %}
{% include "includes/messages.html"%}
{% endblock %}
Then create the message.html file in include folder
<div id="messages">
{% for message in messages %}
<div class="alert alert-{{message.tags }} alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ message }}
</div>
{% endfor %}
</div>
Done so your page will redirect to login page and on that page message will get display.
I have been struggling around the WTF forms for quite a while now. But this error, never seems to go away. I When ever I try to run this code the form never validates
Views :
#bundle.route('/content/add/', methods=['GET', 'POST'])
#bundle.route('/content/add', methods=['GET', 'POST'])
#bundle.route('/content/edit/<posturl>/', methods=['GET', 'POST'])
#bundle.route('/content/edit/<posturl>', methods=['GET', 'POST'])
#fas_login_required
def addcontent(posturl=None):
form = CreateContent()
form_action = url_for('content.addcontent')
if posturl is not None:
content = Content.query.filter_by(slug=posturl).first_or_404()
form = CreateContent(obj=content)
if form.slug.data == posturl and request.method == 'POST' and form.validate():
form.populate_obj(content)
db.session.commit()
return redirect(url_for('content.addcontent',
posturl=posturl, updated="True"))
else:
if request.method == 'POST' and form.validate():
query = Content(form.title.data,
form.slug.data,
form.description.data,
form.media_added_ids.data,
form.active.data,
form.tags.data,
g.fas_user['username'],
form.type_content.data
)
try:
db.session.add(query)
db.session.commit()
# Duplicate entry
except Exception as e:
return str(e)
return redirect(url_for('content.addcontent',
posturl=form.slug.data, updated="True"))
else:
print "Please validate form"
return render_template('content/edit_content.html', form=form,
form_action=form_action, title="Create Content")
Form Class :
# -*- coding: utf-8 -*-
from flask.ext.wtf import Form
from wtforms import TextField, TextAreaField
from wtforms import BooleanField, SelectField, validators
from wtforms.validators import Required
__all__ = ['CreateContent']
class CreateContent(Form):
title = TextField(
'Title', [validators.Length(min=4, max=255)])
slug = TextField(
'Url-Slug', [validators.Length(min=4, max=255)])
description = TextAreaField('Content', [validators.Length(min=4)])
media_added_ids = TextField('media')
type_content = SelectField(u'Content Type',
[Required()],
choices=[('blog', 'Blog Post'),
('media', 'Lecture'),
('doc', 'Documentation')]
)
# Comma seprated media id's
active = BooleanField('Published')
tags = TextField('Tags', [Required()])
# Comma seprated tag id's
And my Template :
{% extends "base.html" %}
{% block title %}
{{ title }}
{% endblock %}
{% block content %}
{% from "_formhelpers.html" import render_field %}
<div id="Create Content">
<center><h3> {{ updated }} </h3></center>
<h2>{{ title }}</h2>
<form method="post" action="">
<fieldset>
<legend></legend>
{{ render_field(form.title) }}
{{ render_field(form.slug ) }}
{{ render_field(form.description ) }}
{{ render_field(form.media_added_ids)}}
{{ render_field(form.type_content) }}
{{ render_field(form.active) }}
{{ render_field(form.tags )}}
</fieldset>
<input type="submit" class="button" value="Save"/>
</form>
</div>
{% endblock %}
Any help will be highly apprieciated
If the CSFR tokens are activated in a flask application setting, a CSFR token is included in each form. If developer has activated the setting and not included it in the form template the flask WTF would automatically reject the request.
The solution to this problem was to the following tag :
{{form.hidden_tag()}}
Once added, a CSFR id is included in the request and sent to the views for validation by the WTForms.
If you haven't included this token no errors will appear in the form.errors dictionary. If you iterate over this dictonary no errors will be show, but the form.validate method will return false.
Flask-WTF adds the CSRF token automatically if it is activated in your Flask settings. If this setting is active and it isn't included in the form submission the submission will be rejected. The solution in this case is to add the hidden_tag field in the template so that it is included in the form submission.
{{form.hidden_tag()}}
First of all I'm glad to be here, I read you lately and i found useful answers here.
This is my first post so please be kind with me, I'm a newbie in programming.
So, I'm writing my 1st web application in Django - a todo app and I don't know how to write the function that does this this. I found something in Django docs and in other related discussions but it doesn't work.
Here's my code:
#models.py
class Task(models.Model):
user = models.ForeignKey(User)
task = models.CharField(max_length=200)
initialized_at = models.DateTimeField(auto_now_add=True)
due_date = models.DateField(default=datetime.now)
done = models.BooleanField(default=False)
def __unicode__(self):
return self.task
#views.py
def edit_task(request, id):
if request.method == 'POST':
task_to_edit = Task.objects.get(pk=task_id)
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm()
return render(request, 'todo/edit_task.html', {'form': form})
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
#edit_task.html
{% block content %}
<form action="/edit_task/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
When I submit the updated form I get this error:
Page not found (404)
Request Method: POST
Request URL: hxxp://127.0.0.1:8000/edit_task/
Using the URLconf defined in jbz.urls, Django tried these URL patterns, in this order:
^admin/
^$ [name='index']
^(?P<task_id>\d+)/$
^(?P<task_id>\d+)/$
^add-task/$
^delete-task/(?P<task_id>\w+)/$
^edit_task/(?P<id>\w+)/$
^done/(?P<task_id>\d*)/$
The current URL, edit_task/, didn't match any of these.
and the root urls.py looks like:
url(r'', include('todo.urls'))
#edit_task.html
{% block content %}
<form action="/edit_task/{{task.id}}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
Notice how I added {{task.id}} expression in <form action="/edit_task/{{task.id}}" method="post">
IMPORTANT NOTE: Substitute {{task.id}} to whatever variable accomplishes this in your template.
The reason why you get the error is because edit_task/ is not getting the other part, task_id to match the regular expression:
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
UPDATE: Also your edit_task view has potential errors as well>
def edit_task(request, id):
task_to_edit = Task.objects.get(pk=id)
if request.method == 'POST':
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm(instance=task_to_edit)
# you don't pass any task variable to the view so the form view
# won't know which task to edit, you'll have to handle that
return render(request, 'todo/edit_task.html', {'form': form, 'task':task_to_edit})
Note: I corrected the code in the view a little. Now the task_to_edit is passed also to the Form to fill the fields when the view is requested via GET. Notice that in order to access to this view, the url in the browser should look like this http://www.example.com/edit_task/2
If other wise you try to access http://www.example.com/edit_task without passing the id you'll get Error 404.
Hope this helps!
I think your pattern for edit task expects an id - task name. Try changing your URL pattern:
'^edit_task/(?P<task_id>\w+)/$'
to
'^edit_task/$'
or providing the task id that you want to edit.
Just add name space to your url and according update your template.
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task', name= "edit_task")
#edit_task.html
{% block content %}
<form action="{% url 'edit_task' task_id %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
I'm reading the Djangobook and I'm on ch 7.There is actually a line that says "#todo - explain CSRF token"
When I was following the examples (I'm pretty sure I've followed them exactly), I cannot get the code to function properly.
Here is my template
<html>
<head>
<title>Contact us</title>
</head>
<body>
<h1>Contact us</h1>
{% if errors %}
<ul>
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<form action="/contact/" method="post">
{% csrf_token %}
<p>Subject: <input type="text" name="subject"></p>
<p>Your e-mail (optional): <input type="text" name="email"></p>
<p>Message: <textarea name="message" rows="10" cols="50"></textarea></p>
<input type="submit" value="Submit">
</form>
</body>
</html>
Here is my view
from django.core.mail import send_mail
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.template import RequestContext
def contact(request):
errors = []
if request.method == 'POST':
if not request.POST.get('subject', ''):
errors.append('Enter a subject.')
if not request.POST.get('message', ''):
errors.append('Enter a message.')
if request.POST.get('email') and '#' not in request.POST['email']:
errors.append('Enter a valid e-mail address.')
if not errors:
send_mail(
request.POST['subject'],
request.POST['message'],
request.POST.get('email', 'noreply#example.com'),
['siteowner#example.com'],
)
return HttpResponseRedirect('/contact/thanks/')
return render(request, 'contact_form.html',
{'errors': errors}, context_instance=RequestContext(request))
This is the error I'm getting
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
- Your browser is accepting cookies.
- The view function uses RequestContext for the template, instead of Context.
- In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
- If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.
EDIT******
I discovered that I can view the source code for my form and the csrf_token isn't being inserted even though I have it in my template. I looked up common solutions. Some people suggested I do this
return render_to_response('contact_form.html',
{'errors': errors}, context_instance=RequestContext(request))
But this doesn't work for me either.
I just checked my settings.py and I see 2 middlewares added not just CsrfViewMiddleware -
MIDDLEWARE_CLASSES = (
...
‘django.middleware.csrf.CsrfViewMiddleware’,
‘django.middleware.csrf.CsrfResponseMiddleware’,
)
Try adding more.