I am just building a simple HTML form with POST method and unfortunately I am finding CSRF verification error.
This is just a simple html form using POST method on localhost. There are no cross sites involved. I could definitely fix it by using csrf_token but I still don't understand why django is asking me for that..
There are no re-directions/ iframes involved here...
So, why this is happening?? is this normal to all ??
# Also tried using RequestContext(request) but there isn't any change in the error
#settings.py
'django.middleware.csrf.CsrfViewMiddleware' in MIDDLEWARE_CLASSES
#views.py
# url for home page is "" i.e, http://127.0.0.1:8000/
def HomePage (request):
if request.method == "POST":
form = myForm(request.POST)
if form.is_valid():
data = form.cleaned_data
context = { "myForm" : myForm(choices),
"values" : data,
}
return render_to_response("home.html", context)
else:
form = myForm(choices)
context = {"myForm" : form}
return render_to_response("home.html", context)
# home.html
<div id="pingmeeForm">
<form action="" method="post">
<table>
{{myForm.as_table}}
</table>
<input name="enter" type="submit" value="enter"/>
</form>
{{values}}
</div>
# forms.py
class myForm (forms.Form):
def __init__(self, my_choices,*args, **kwargs):
super(myForm, self).__init__(*args, **kwargs)
self.fields['Friends'] = forms.ChoiceField(choices=my_choices)
message = forms.CharField()
If you do a post request, you typically change the state of the server. If you change the state of the server, you don't want to allow other sites to do so. To protect against other sites issueing post-requests on your server, you add csrf protection. Therefore the solution should (imho) never be to remove the Csrf protection. Depending on the situation, either of the following two is the case:
Your post request does not change the state. In that case, make it a get request.
Your post request changes the state. You need CSRF.
The error message you got but didn't show explains exactly what you are doing wrong: you should ensure that
the view function uses RequestContext
for the template, instead of Context.
Related
I know this question was asked before, but none worked for me. I have this code that I want it to be executed when a button is clicked and a message is passed
import time
from sinchsms import SinchSMS
number = '+yourmobilenumber'
message = 'I love SMS!'
client = SinchSMS(your_app_key, your_app_secret)
print("Sending '%s' to %s" % (message, number))
response = client.send_message(number, message)
message_id = response['messageId']
response = client.check_status(message_id)
while response['status'] != 'Successful':
print(response['status'])
time.sleep(1)
response = client.check_status(message_id)
print(response['status'])
Basically, what I need is to add an input in a template "HTML File", this input get passed to the message variable in the code above, same with the number. I can easily do that with instances, but how can the below get executed when a button is clicked from the form in the template?
I'm kinda newbie in Django and still finding my way
Here is the tutorial that explains how to make the python file, but execute it from the shell, not a django application.
I hope I was clear describing my problem and any help would be appreciated!
All you need is a form with a message field. In a view, you want to show that form and when the user press submit, you want to execute your script.
Here is some pseudo-code:
urls.py
url('^my-page/' my_views.my_view, name='my-page'),
forms.py
SmsForm(forms.Form):
message = fields.CharField(...)
my_views.py
def my_view(request):
form = SmsForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
send_sms(form.cleaned_data['message']) # do this last
messages.success(request, "Success")
return HttpResponseRedirect(request.path)
else:
messages.warning(request, "Failure")
return render(request, 'my_template.html', {'form': form})
Check the Django documentation about urls, views, forms and messages and proceed step by step:
get the page to load
get the form to load
get the form submission to work and simply show "Success" or "Failure"
finally, write the send_sms function (you've almost done it)
Lets start from the dust cloud.
What you are asking is mostly about how the web pages work. You need to know how to pass parameters using HTML. There are lots of ways to do it. But with django there is a pattern.
You need a url, and a view to catch any requests. Then you need to create a template and a form inside it. With this form you could create some requests to send data to your view.
To create you need to edit urls.py inside your project add an url:
urls.py
from django.conf.urls import url
from my_app.views import my_view
urlpatterns = [
...
url(r'^my_url$', my_view, name='my_view')
...
]
For more about urls please look at URL dispatcher page at documentation.
Then create your view inside your app which is my_app in my example. Edit my_app/views.py
my_app/views.py
from django.http import HttpResponse
def my_view(request):
return HttpResponse('IT WORKS!')
This way you get a working view which could be accessed with path /my_url. If you run ./manage.py runserver you could access your view from http://localhost:8000/my_url.
To create a form you need to create a template. By default django searches app directories for templates. Create a templates directory in your app, in our case my_app/templates and create an HTML file inside. For example my_app/templates/my_form.html. But i advice to create one more directory inside templates directory. my_app/templates/my_app/my_form.html. This will prevent template conflicts. You can check Templates page at documentation for more.
my_app/templates/my_app/my_form.html
<html>
<body>
<form action="/my_url" method="POST">
{% csrf_token %}
<input type="text" name="number">
<input type="text" name="message">
<input type="submit" value="Run My Code">
</form>
</body>
</html>
This is the one of the ways of creating your form. But I do not recommend it. I will make it prettier. But first lets "Make it work", edit your views.py:
csrf_token is a django builtin template tag, to put CSRF token into your form. By default django requires CSRF tokens at every post
request.
my_app/views.py
from django.http import HttpResponse
from django.shortcuts import render
def my_view(request):
if request.method == 'GET':
return render('my_app/my_form.html')
elif request.method == 'POST':
# get post parameters or None as default value
number = request.POST.get('number', None)
message = request.POST.get('message', None)
# check if parameters are None or not
if number is None or message is None:
return HttpResponse('Number and Message should be passed')
# your code goes here
...
return HttpResponse('Your code result')
Till this point the purpose of this answer was "Making it work". Lets convert it nice and clean. First of all we would create Form. Forms are like models, which helps you create forms as objects. It also handles form validations. Forms are saved inside forms directory generally. Create my_app/forms.py and edit it:
my_app/forms.py
from django import forms
class MyForm(forms.Form):
number = forms.CharField(max_length=15, required=True)
message = forms.CharField(max_length=160, required=True)
Put your form inside your template:
my_app/templates/my_app/my_form.html
<html>
<body>
<form action="{% url 'my_view' %}" method="POST">
{% csrf_token %}
{{ form }}
</form>
</body>
</html>
Besides the form, the action of the HTML form tag is also changed.
url template tag is used to get url form url name specified in urls.py.
Instead of url tag, {{ request.path }} could have been used.
Create a form instance and pass it to the template rendering:
my_app/views.py
from django.http import HttpResponse
from django.shortcuts import render
from .forms import MyForm
def my_view(request):
if request.method == 'GET':
form = MyForm()
return render('my_app/my_form.html', {'form': form})
elif request.method == 'POST':
form = MyForm(request.POST)
# check if for is not valid
if not form.is_valid():
# return same template with the form
# form will show errors on it.
return render('my_app/my_form.html', {'form': form})
# your code goes here
...
return HttpResponse('Your code result')
You can use class based vies to write your view, but it's not necessary. I hope it helps.
You can create a view that takes up query parameters from the url and use it for further implementation. Then you can create a link/button in the html template which can redirect you to that url. For example:
in urls.py:
url(r'^run_a/(?P<msg>\w{0,25})/(?P<num>\w{0,25})/$', yourcode, name='get_msg'),
in template:
submit
in views.py:
def get_msg(request,msg,num):
message=msg
number=num
#rest of the code
Hope this helps :)
Posting values from Advanced Rest client to Django's definition returns "Forbidden(403)" alert
looks like CSRF token is missing in the header, What can be done to get rid of this issue? Below is my definition to receive the POST values
def saveToDb(request):
c = {}
c.update(csrf(request))
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form_unique_id = form.cleaned_data['form_id']
form_meta_data = form.cleaned_data['form_content']
meta_data = FormMetaData.objects.create(
form_id=form_unique_id,
form_content=form_meta_data
)
meta_data.save()
result = FormMetaData.objects.all()
return render(request, "form_saved.html", {'result': result})
There is no issue in the definition as it works well with form input
Post to Django From Advanced Rest Client with CSRF Token:
Set CSRF Token for the key "X-CSRFToken" in the Header Section, add the key-value pairs in the body section, Select the Content type as "application/x-www-form-urlencoded" and click the Send Button
Post to Django from Advanced Rest Client without CSRF Token: Add the key-value pairs in the body section, Select the Content type as "application/x-www-form-urlencoded" and click the Send Button.
Note:
Please make sure to set "#csrf_exempt" for the definition to which you post values
as shown below
You have to give {% csrf_token %} in your html;
<html>
<form method="post">
{% csrf_token %}
</form>
</html>
I'm submitting a form and instead of redirecting to a success url I would like to just show "Form has been submitted" in text on the page when the form has been submitted. Does anyone know how I can do so?
In your view:
if request.POST:
# validate form, do what you need
if form_is_valid():
message = 'Form has been submitted'
return render_to_response('path/to/template.html', {'message': message})
And then use code in your template like:
{% if message %}
<h4>{{ message }}</h4>
{% endif %}
Honestly, this isn't a Django-specific issue. The problem is whether you are doing a normal form submission or using AJAX.
The basic idea is to POST to your form submission endpoint using AJAX and the form data, and in the Django view, merely update your models and return either an empty 200 response or some data (in XML, JSON, small HTML, whatever you need). Then the AJAX call can populate a success message div on success, or display a failure message if it gets back a non-200 response.
Modify your view to return an HttpResponse object with the text you want as its parameter, after you have validated the request. See the example below.
from django.http import HttpResponse
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponse('Form has been submitted.')
I receive this message:
CSRF token missing or incorrect.
In most forums, the tell you to get the {% csrf_token %} in the form, and i do have it.
Also i have in my settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.csrf",
"django.contrib.auth.context_processors.auth",
)
I am using jinja, which didn't seem to use CSRF, but then i installed django registration and i got lost, since, it seems to be using some other views, that i don't have access to so to say, they are not written by me, and i can't figure out where they are. "standard auth views" as they call them. So i am unable to add "RequestContext".
Any ideas what's going on and how I can get it going? thanx
You might have to rewrite the django-registration view manually. Looks like there's an issue with how Jinja likes to do things and how Django wants to configure template loaders..
To look at the standard auth views, just look under "site-packages" in your python installation.
You could try wrapping the standard auth views like this:
from django.contrib.auth.views import login, logout
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def my_wrapped_login_view(request):
return login(request)
#csrf_protect
def my_wrapped_logout_view(request):
return logout(request)
I basically imported Django's standard auth views and called them with my own, which have the csrf_protect decoration. It's worth a shot.
Have you also got the standard Django Templating system installed? That will be required for most apps that are distributed with templates.
For CSRF, a context processor inserts the variable 'csrf_token' into the response context that it retrieves from the middleware if enabled. Now all you have to do, is make sure that it's apart of your form.
This is straight out of django.core, and is subject to change at any time.
if csrf_token:
if csrf_token == 'NOTPROVIDED':
return mark_safe(u"")
else:
return mark_safe(u"<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='%s' /></div>" % csrf_token)
However, seeing that, all you really need to know is that you have to have an input type named csrfmiddlewaretoken with the value of context.get('csrf_token','') within your form and that's all she wrote.
This answer isn't specific to django-registration, but just using Django with Jinja2 in general.
Django's CsrfViewMiddleware sets the csrf_token cookie if it determines that you have accessed the csrf_token context member. Unfortunately, Jinja2 rendering doesn't occur until after Django's middleware executes. As a result, the cookie doesn't get set, and therefore does not match the form, and you will get the 403 error.
To get around this issue, you need to access context['csrf_token'] at some point before you finish processing the response.
If you're using class-based views, you can create a CsrfProtectMixin:
class CsrfProtectMixin(object):
def render_to_response(self, context, **response_kwargs):
# Csrf processing happens when using a RequestContext.
# Be sure to use one.
if not isinstance(context, RequestContext):
context = RequestContext(self.request, context)
# Force access to csrf_token due to the way jinja2 renders the template
# after middleware has finished processing. Otherwise, the csrf cookie
# will not be set.
str(context.get('csrf_token'))
return super(CsrfProtectMixin, self).render_to_response(context, **response_kwargs)
And then in your view class:
class MyView(CsrfProtectMixin, TemplateView):
def get(self, request, *args, **kwargs):
context = {}
return self.render_to_response(context)
If you're not using class-based views, you can do something like:
def my_view(request):
context = RequestContext(request)
str(context['csrf_token']) #force access to the csrf_token
return render_to_response('template.html', context)
Or perhaps monkey patch render_to_reponse with the logic in the class, above.
The most straightforward answer to this one is to just put {% csrf_token %} within the form tag in your template/html.
I just switched off the csrf middleware in the settings like so, and now it works:
#'django.middleware.csrf.CsrfViewMiddleware',
I'm writing a Django admin action to mass e-mail contacts. The action is defined as follows:
def email_selected(self,request,queryset):
rep_list = []
for each in queryset:
reps = CorporatePerson.objects.filter(company_id = Company.objects.get(name=each.name))
contact_reps = reps.filter(is_contact=True)
for rep in contact_reps:
rep_list.append(rep)
return email_form(request,queryset,rep_list)
email_form exists as a view and fills a template with this code:
def email_form(request,queryset,rep_list):
if request.method == 'POST':
form = EmailForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email','noreply#localboast'),['redacted#email.com'],
)
return HttpResponseRedirect('thanks')
else:
form = EmailForm()
return render_to_response('corpware/admin/email-form.html',{'form':form,})
and the template exists as follows:
<body>
<form action="/process_mail/" method="post">
<table>
{{ form.as_table }}
</table>
<input type = "submit" value = "Submit">
</form>
</body>
/process_mail/ is hardlinked to another view in urls.py - which is a problem. I'd really like it so that I don't have to use <form action="/process_mail/" method="post"> but unfortunately I can't seem to POST the user inputs to the view handler without the admin interface for the model being reloaded in it's place (When I hit the submit button with , the administration interface appears, which I don't want.)
Is there a way that I could make the form POST to itself (<form action="" method="post">) so that I can handle inputs received in email_form? Trying to handle inputs with extraneous URLs and unneeded functions bothers me, as I'm hardcoding URLs to work with the code.
You can use django's inbuilt url tag to avoid hardcoding links. see...
http://docs.djangoproject.com/en/dev/ref/templates/builtins/#url
Chances are you'd be better off setting up a mass mailer to be triggered off by a cron job rather than on the post.
Check out the answer I posted here
Django scheduled jobs
Also if you insist on triggering the email_send function on a view update perhaps look at
http://docs.djangoproject.com/en/dev/topics/signals/