CSRF verification failed despite following documentation - django

I'm trying to implement an ajax function that will execute a database query based on the id value of a drop down selection.
The HTML of the drop down list is
<form method = "POST" action="" >{% csrf_token %}
<select name = "parentorgs" id = "parentorgs">
{% for org in parentorg_list %}
<option value = "{{org.parentorg}}" id = "{{org.parentorg}}" >{{ org.parentorgname }}</option>
{% endfor %}
</select>
</form>
A jQuery change() function is used to get the ID of the selection and passes it to
function getData(id) {
$.ajax({
type : "POST",
url : "getData/",
data : {"parentorg" : id},
datatype: "json",
success : function(data) {
console.log(data)
}
});
}
which in turn calls the view function
from django.shortcuts import render_to_response, render
from django.core.context_processors import csrf
def getData(request):
c = {}
c.update(csrf(request))
return render_to_response("app/index.html", c)
Firebug shows that the request is going through via POST, and the method URL is valid. In addition, the URL of this method has been added to urls.py.
At this time, its not doing anything, as I just want to see the response from the method. This method is intended to execute a model query and return the results.
Each time an item is selected in the dropdown, I get an error 403 describing that the view uses ResponseContext rather than Context for the template.
What needs to be done to resolve this issue?

According to the doc
If you’re using Django’s render_to_response() shortcut to populate a template with the contents of a dictionary, your template will be passed a Context instance by default (not a RequestContext). To use a RequestContext in your template rendering, pass an optional third argument to render_to_response(): a RequestContext instance. Your code might look like this:
from django.template import RequestContext
def getData(request):
c = {}
c.update(csrf(request))
return render_to_response("app/index.html", c, context_instance=RequestContext(request))

Related

Django Render HTML via AJAX - Missing Context Variable Data

In my Django web app, I'm trying to dynamically update only a certain section of my page via AJAX, but doing so by returning/replacing HTML in a child template ({% include 'keywords.html' %}). I understand that I can (and maybe should) return a JsonResponse (and I have done so successfully), but I'd like to try and get the below implementation working (as others seem to have).
The view successfully returns the HTML to the AJAX response, but lacking the data contained in the keywords context variable.
templates/index.html
...
<div id="keywords">
{% include 'keywords.html' %}
</div>
...
templates/keywords.html
<div id="keywords">
{% if keywords %}
{% for keyword in keywords %}
<p>{{keyword.word}}</p>
{% endfor %}
{% endif %}
</div>
views.py
def add_keyword(request):
if request.method == 'POST':
form = KeywordForm(request.POST)
if form.is_valid():
...
keywords = Keywords.objects.values()...
print(keywords) # this works, contains a queryset with data
context = {
keywords: keywords,
}
# i've also tried return HttpResponse(render_to_string(...))
# with same result
return render(request, 'keywords.html', context))
index.js
// i've also tried jquery .load()
$.ajax({
url: data.url,
type: "POST",
data:
{
keyword: keyword,
csrfmiddlewaretoken: data.csrf_token
},
success: function(data) {
$("#keywords").html(data);
}
});
AJAX Response data:
<div id="keywords">
</div>
What might I be missing, or doing wrong?
In your context you are missing quotes, when returning the page you have one extra parentheses. It works on my system.
You can render your template with context data using the loade and context
it will do first templates using jinja context will render in html then return final html text then you can pass using JsonResponse
try following stuff then let me know
#view.py
from django.template import context,loader
...
def render_view(request):
if request.method == 'GET':
form = KeywordForm(request.POST)
if form.is_valid():
keywords = Keywords.objects.values()
print(keywords) # this works, contains a queryse
context = {
keywords: keywords,
}
template = loader.get_template('keywords.html')
html = template.render(context)
print(html)
return JsonResponse({'html':html},status=200,content_type="application/json")
#in ajax call success method you should render
success: function(data) {
$("#keywords").html(data);
//or
//ordocument.getElementById('keywords').innerHTML=data;
}
if works or not let me know?

Django: CSRF is incorrect or missing

I have seen a number of forums and posts but still couldn't get the handle of it. Here in django doc, it says
The CSRF middleware is activated by default in the MIDDLEWARE setting. If you override that setting, remember that 'django.middleware.csrf.CsrfViewMiddleware' should come before any view > middleware that assume that CSRF attacks have been dealt with.
If you disabled it, which is not recommended, you can use csrf_protect() on particular views you want to protect (see below).
In any template that uses a POST form, use the csrf_token tag inside the > element if the form is for an internal URL, e.g.:
form action
{% csrf_token %}
Based on that, in my html template I did simply:
<form id='frm' name='frm' method="post" action="{% url 'gettip' %}" >
{% csrf_token %}
<input type="text" name="tipid" name="tipid">
<input type="submit" value="Get Tip Value"/>
</form>
I expected the CSRF_token to create the hidden element since the middleware is already loaded. I see no element in the form and I get CSRF error.
The form is not associated with any model. I haven't used forms.py either. My current view is simply to output something:
def gettip(request):
if request.POST:
return HttpResponse('You requested a tip')
#from a weblink, i was told to add the following but it made no difference
context = {}
return render_to_response('tip.html',context, context_instance=RequestContext(request))
The error I am getting is obviously CSRF missing cos the hidden element is not there at all.
I am migrating from PHP and this is giving me a hard time. Though my form is not for login purposes, I couldn't get this one to work either for the same error. I am on django 1.10 and just want to get a positive response when form is submitted.
Don't use render_to_response, it's obsolete. Use render instead.
from django.shortcuts import render
def gettip(request):
if request.POST:
return HttpResponse('You requested a tip')
context = {}
return render(request, 'tip.html', context)
If the template containing the form is rendered by another view, you'll have to fix that view as well.

Proper way of using url patterns

I've created a form which by submit uploads an item to the database. The problem is that if I press f5 it'll submit the form again, because of the URL is now different.
I have these two url patterns
urlpatterns = [
url(r'(?i)^CMS/$', views.CMS, name='CMS'),
url(r'^createItem/$', views.createItem, name='createItem')
]
and my view looks like this
def CMS(request):
form = itemCreateForm()
context = {
'form' : form,
'message' : 'Content Manage Site'
}
return render(request, 'CMS.html', context)
def createItem(request):
f = itemCreateForm(request.POST)
if f.is_valid():
f.save()
pass
form = itemCreateForm()
context = {
'form' : form,
'message' : 'ItemCreated!'
}
return render(request, 'CMS.html', context)
the CMS.html
{% if message %}
{{ message }}
{% endif %}
<div class='newItemFields'>
<form action="{% url 'kar:createItem' %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
</div>
my form
class itemCreateForm(ModelForm):
class Meta:
model = item
fields = ['name', 'type', 'price']
I start at homepage/CMS/ and fill in the form and press submit, and view function createItem runs and creates and saves the object in the database. And sends the user to homepage/CMS/createItem. And now everytime the user press f5 the createItem function will run again and insert another object into the database with the same values as the previous one, even though the input fields are empty (can't wrap my head around that).
I also twice write form = itemCreateForm() which I believe is dubious?
What I'd like to do is after createItem is run, it should send the user back to homepage/CMS/ and not homepage/CMS/createItem. Would that be the proper way to do it? Or is there a smart way of doing this.
At the end of your createItem function, you are rendering HTML of the page rather than redirecting. Instead, you need to do
return HttpResponseRedirect(reverse('kar:index'))
You will need to import HttpResponseRedirect and reverse which is used to resolve the URL through its name.
Check this out: https://docs.djangoproject.com/en/1.10/topics/forms/#the-view
What I'd like to do is after createItem is run, it should send the
user back to homepage/CMS/ and not homepage/CMS/createItem. Would that
be the proper way to do it? Or is there a smart way of doing this.
That would indeed be the proper and smart way to do it. Have one view handle both GET and POST and then redirect after successful form submission. This ensures that the user can't resubmit the form merely by refreshing. And you address your concern about repeating your code.
urlpatterns = [
url(r'(?i)^$', views.index, name='index'),
url(r'^createItem/$', views.createItem, name='createItem')
]
Then combine your views
def createItem(request):
if request.method == 'POST':
f = itemCreateForm(request.POST)
if f.is_valid():
f.save()
return HttpResponseRedirect('/homepage/CMS/')
else :
form = itemCreateForm()
context = {
'form' : form,
'message' : 'Content Manage Site'
}
return render(request, 'CMS.html', context)
Note that the code is now shorter, it gives proper feedback to the user when the form is not valid. And you can't refresh to submit the for twice. We need a small change to the template
<div class='newItemFields'>
<form action=method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
</div>
The message display part isn't needed anymore

In Django, how to pass selected dropdown value from template to view?

I searched for so long for a solution to this, but still can't find any. I have a big form in my template, which is actually composed of a bunch of model forms. One field in that big form is not part of a form, but is a single dynamic drop down menu populated from a table called "Institutions" in views.py as such: Institutions.objects.all()
Here is the part from views.py:
def submission_form(request):
institutions = Institution.objects.all()
if request.method == 'POST':
abstractform = AbstractForm(request.POST)
authorform = AuthorForm(request.POST)
# Here I want code: if selected institution is this, then do that
if abstractform.is_valid() and authorform.is_valid()
new_abstract = abstractform.save()
new_author = authorform.save()
else:
return render(request, 'records/submission_form.html', {'abstractform': abstractform, 'authorform': authorform, 'institutions':institutions })
This is the drop down in my template:
<select id="ddlInstititions">
<option value="%">---------</option>
{% for entry in institutions %}
<option value="{{ entry.id }}">{{ entry.name }}</option>
{% endfor %}
</select>
My question is: Is it possible to pass that selected entry.name to the view so I can use it there? If not, what do you recommend doing instead?
Any help would be much appreciated!
In order for any form element to be sent in the POST, you need to have a name attribute. So it should be <select id="ddlInstititions" name="institutions">.
What's passed to the view in the POST is the value attribute of each option element. Currently, you've set that to entry.id, so it's the ID that will be in the POST. You can either use that to look up the Institution object and get the name, or you can change the form so you put entry.name directly in the value attribute.
You can use jQuery's $.ajax() for this.
In your Javascript, you can bind an event handler to #ddlInstititions via
$("#ddlInstitions").on("change", function(){
var selectedValue = $(this).text();
$.ajax({
url : "insititionsSelectHandler/",
type : "GET",
data : {"name" : selectedValue},
dataType : "json",
success : function(){
}
});
});
What this will do is when you make a select event on the dropdown, it will fire this event handler. You will have to define this URL in your `urls.py' like
(r'^/institionsSelectHandler/$', views.insititionsSelectHandler),
and you can get the value inside the view method like
def insititionsSelectHandler(request):
key = request.GET["name"]
...
...
...
#and return your results as a HttpResponse object that contains a dict
return HttpResponse(simplejson.dumps({"success" : "true", "message" : ... }, mimetype = "application/json")

How can i return a Django ModelForm through an Jquery Ajax call?

Initially i am loading a modelform with an instance in the template end. But i have to change the instance upon some action using ajax and then refresh the form in the template end. Please suggest me is there any way to do that?
Normally, the server view uses a ModelForm to render a HTML snippet representing an instance of a Model (i.e. {{ myform.as_p }} or similar) that is then placed in a larger template representing an entire HTML document and finally sent to the client.
You need to create a second view that will render and return only the HTML snippet representing the form. From your original template you can then create an ajax call to your new view, which will return the forms HTML. You can replace your existing form with this via jQuery.
view:
def my_second_form(request):
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
...
else:
form = MyForm()
return render(request, 'my_second_form.html', {
'form': form,
})
template:
<form action="/url/to/my_second_form/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
#djanog function.
def get_doctor_Data(request):
get_doctor = Doctor.objects.get(id=request.GET.get('dept_id'))
# Set initial value of django forms input and send as ajax respons
# If you getting any type of error so use form_name.as_p() method.
edit_form = AddDoctorForm(initial={'name':get_doctor.name, 'dep_id':get_doctor.id})
return HttpResponse(edit_form)
// Ajax method call.
$.ajax({
url: '/department/get_department_Data/',
type: 'GET',
data : {'dept_id': $(this).attr('id')},
success:(data)=>{
if(data){
// open modal
$('#basicModal').modal('show');
// Django forms get using ajax
$('#editForm').html(data)
}
}
})