POST request not behaving as intended - ajax

I've been trying to get my button to send a POST request to the submitted URL, which does a write back to the database. The application looks like the POST request gets sent, but after hitting the button my URL never changes and the print at the submitted URL appears to be an empty set.
This is my jquery/ajax call for the button:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<button class="btn btn-primary my_select" type="submit">Request Access</button>
<script>
$(document).ready(function () {
$('form').on('submit', function (e) {
e.preventDefault();
var phi = $('#phi').val();
var accesslevelid = $('#accesslevelid').val();
$.ajax({
url: "{% url 'submitted' %}",
headers: { 'X-CSRFToken': '{{ csrf_token }}' },
data: {
phi: phi,
accesslevelid: accesslevelid,
},
type: 'POST',
success: function (result) {
// do something with result
},
});
});
});
</script>
I'm expecting my POST of the Application List, PHI flag, and Access Level gets sent as a POST to my submitted URL. My view for submitted is the following:
def submitted(request):
owner = User.objects.get (formattedusername=request.user.formattedusername)
checkedlist = request.POST.getlist('report_id')
coid = User.objects.filter(coid = request.user.coid).filter(formattedusername=request.user.formattedusername)
facilitycfo = QvDatareducecfo.objects.filter(dr_code__exact = coid, active = 1, cfo_type = 1).values_list('cfo_ntname', flat = True)
divisioncfo = QvDatareducecfo.objects.filter(dr_code__exact = coid, active = 1, cfo_type = 2).values_list('cfo_ntname', flat = True)
print (f"checkedlist prior to post:{checkedlist}")
selectedaccesslevel = request.POST.get('accesslevelid')
selectedphi = request.POST.get('phi')
if request.method == 'POST':
for i in checkedlist:
requestsave = QVFormAccessRequest(ntname = owner.formattedusername, first_name = owner.first_name, last_name = owner.last_name, coid = owner.coid, facility = owner.facility, title = owner.title
,report_id = i, accesslevel_id = selectedaccesslevel, phi = selectedphi , access_beg_date = '2017-01-01 00:00:00', access_end_date = '2017-01-31 00:00:00')
requestsave.save()
print (f"postlist:{checkedlist}")
print (f"accesslevel:{selectedaccesslevel}")
print (f"phi:{selectedphi}")
return JsonResponse({'is_success':True})
My post looks like it occurs when I press my button:
[]
[12/Dec/2017 08:54:45] "POST /account/submitted/ HTTP/1.1" 200 1149
However, the URL doesn't switch to submitted. My list for checkedlist appears to be an empty set. When visiting submitted and having my print statements occur, i get nothing like the POST never occurred.
My form action is the following:
<form action = "{% url 'submitted' %}" form method = "POST">
{% csrf_token %}
{{ form.as_p}}

ajax is build to do background client server operation or load part of the page dynamic to avaid heavy requests
Example
most of social medias feeds use ajax. when you scroll the view a ajax request is send to server to retrieve the next feed .
in your case the data is posted to server successfully. but change the URL is not available by server at this point but you can do this with a trick ...
in your view.py file
from django.http import JsonResponse
if request.method == 'POST':
for i in checkedlist:
requestsave = QVFormAccessRequest(ntname = owner.formattedusername, first_name = owner.first_name, last_name = owner.last_name, coid = owner.coid, facility = owner.facility, title = owner.title
,report_id = i, accesslevel_id = selectedaccesslevel, phi = selectedphi , access_beg_date = '2017-01-01 00:00:00', access_end_date = '2017-01-31 00:00:00')
requestsave.save()
print (checkedlist)
print(selectedaccesslevel)
print(selectedphi)
return JsonResponse({'is_sucess':True})
this JsonResponse object will send back the data ajax.
success: function (result) {
if(result.is_sucess){
document.location = 'you url to direct page at' //
}
},
this job can be done using direct post to url and then redirecting to other url i. will leave this for now

Related

Django - Making an Ajax request

Im having a hard time figuring out how to integrate this ajax request into my view. I'm still learning how to integrate django with ajax requests.
My first question would be: Does the ajax request need to have its own dedicated URL?
In my case I am trying to call it on a button to preform a filter(Preforms a query dependent on what is selected in the template). I have implemented this using just django but it needs to make new request everytime the user preforms a filter which I know is not efficient.
I wrote the most basic function using JQuery to make sure the communication is there. Whenever the user changed the option in the select box it would print the value to the console. As you will see below in the view, I would to call the ajax request inside this view function, if this is possible or the correct way of doing it.
JQuery - Updated
$("#temp").change( function(event) {
var filtered = $(this).val();
console.log($(this).val());
$.ajax({
url : "http://127.0.0.1:8000/req/ajax/",
type : "GET",
data : {
'filtered': filtered
},
dataType: 'json',
success: function(data){
console.log(data)
},
error: function(xhr, errmsg, err){
console.log("error")
console.log(error_data)
}
});
Views.py
def pending_action(request):
requisition_status = ['All', 'Created', 'For Assistance', 'Assistance Complete', 'Assistance Rejected']
FA_status = RequisitionStatus.objects.get(status='For Assistance')
current_status = 'All'
status_list = []
all_status = RequisitionStatus.objects.all()
status_list = [status.status for status in all_status]
# This is where I am handling the filtering currently
if request.GET.get('Filter') in status_list:
user_req_lines_incomplete = RequisitionLine.objects.filter(Q(parent_req__username=request.user) & Q(status__status=request.GET.get('Filter')))
current_status = request.GET.get('Filter')
else:
user_req_lines_incomplete = RequisitionLine.objects.filter(parent_req__username=request.user).exclude(status__status='Completed')
user_reqs = Requisition.objects.filter(par_req_line__in=user_req_lines_incomplete).annotate(aggregated_price=Sum('par_req_line__total_price'),
header_status=Max('par_req_line__status__rating'))
return render(request, 'req/pending_action.html', { 'user_reqs':user_reqs,
'user_req_lines_incomplete':user_req_lines_incomplete,
'requisition_status':requisition_status,
'current_status':current_status,
'FA_status':FA_status})
def filter_status(request):
status = request.GET.get('Filter')
data = {
'filtered': RequisitionLine.objects.filter(Q(parent_req__username=request.user) & Q(status__status=status)),
'current_status': status
}
return JsonResponse(data)
Urls.py
path('pending/', views.pending_action, name='pending_action')
First: you have to divide your template to unchangeable part and the part that you want to modify with your filter.
Second: for your goal you can use render_to_string. See the followning link https://docs.djangoproject.com/en/2.1/topics/templates/#usage
code example (views.py):
cont = {
'request': request, #important key-value
'your_models_instances': your_models_instances
}
html = render_to_string('your_filter_template.html', cont)
return_dict = {'html': html}
return JsonResponse(return_dict)
In your js file you need to determine relative url "{% url 'name in yours url file'%}"
And in success you need to add next line:
success: function(data){
$(".filter-block").html(data.html);
}
i hope it will help you! Good luck!

Multiple ajax requests kill django server

I have a single view which scrolls through user data. There are next and previous buttons to scroll. When user presses next, ajax sends the user id to the django view and displays the data.
If user clicks the next button two or three times consecutively (which they usually do), the calls get aborted and server is killed.
$("#new").click(function() {
$.ajax({
type:'POST',
url:'/new/',
data:{
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success:searchSuccess,
dataType: 'html'
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#myForm').html(data);
}
This is the view.
def master_detail_next(request):
def decrement_voucher_id(form_id):
voucher_id = str(int(form_id) - 1).zfill(4)
return voucher_id
if request.method == 'POST':
form_id = request.POST['voucher_id']
voucher_id = decrement_voucher_id(form_id)
voucher_id = get_decremented_voucher_id(voucher_id)
else:
voucher_id = ''
# Inline forms
author = TmpPlInvoice.objects.get(voucher_id=voucher_id)
author_form = TmpForm(instance=author)
BookFormSet = inlineformset_factory(TmpPlInvoice, TmpPlInvoicedet,
exclude=('emp_id', 'voucher', 'lineitem', 'id',),
form=TmpFormDetForm, )
formset = BookFormSet(instance=author)
totalform = TmpFormTotal(instance=author)
postform = CheckPostedForm(instance=author, posted=author.posted)
return render(request, 'form.html', {'form': author_form, 'formset': formset, 'formtotal': totalform, 'postform': postform})
How can i avoid that? What is that i am doing wrong?

Django Ajax Form Works but Throws 500 (Internal Server Error)

I've researched this to death, but have not found exactly what I need to get the last part of my form completed.
I have a simple 2-field form in my footer for newsletter signup. I am utilizing an inclusion_tag since I need to include the form on every page.
The form works; with a couple of hitches, for arguments sake, it works, I hit submit and the email is sent to me. The problem is that I am getting a 500(internal server error) in console on the ajax url. I am assuming that its not really supposed to redirect to the url, but rather just process the form. Below is my code; I hope someone can easily point out my issues. Thanks.
Inclusion Tag
#register.inclusion_tag('includes/cta_form.html', takes_context=True)
def footer_newsletter_signup(context):
title = 'Newsletter Signup'
form = CTASignupForm()
context = {
'form': form,
'title': title,
}
return context
Ajax
$('#sendSignupForm').click(function (e) {
e.preventDefault();
var mForm = $('#signupForm').serialize();
console.log(mForm);
$.ajax({
type: 'POST',
url: '{% url 'pages:cta_signup' %}',
data: mForm,
success: function (data) {
$("input").val('')
},
error: function (data) {
$("input").addClass('error')
}
})
})
cta_form.html
<form action="{% url 'pages:cta_signup' %}" method="POST" id="signupForm">
{% csrf_token %}
{{ form.name }}
{{ form.email }}
<button class="btn btn-black no-margin-bottom btn-small" type="submit" id="sendSignupForm">Submit</button>
</form>
View
def cta_signup(request):
if request.method == "POST":
form = CTASignupForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
subject = 'This is a response from Soledad Footer Signup Form'
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [from_email, 'charles#netfinity.net']
ctx = {
'subject': subject,
'name': name,
'email': email
}
message = get_template('email_forms/cta_signup_email.html').render(Context(ctx))
msg = EmailMessage(subject, message, from_email=from_email, to=recipient_list)
msg.content_subtype = 'html'
msg.send()
messages.success(request, "Thank you, we received your message")
if form.errors:
json_data = json.dumps(form.errors)
return HttpResponseBadRequest(json_data, content_type='application/json')
else:
raise Http404
Screenshot of Console Error
A view must always return a response. You don't, if the form is valid; that's a server error.
Return HttpResponse() at the end of the is_valid block.

Why does Django 1.7 tell me that the csrf_token was not provided in the context after sending a successful ajax request?

When I get the template and render a form in my Django 1.7 app, I get no errors on the Python server console. I can submit the form using AJAX using the X-CSRFHeader recommendation provided in the Django documentation, and the request is successful and does not throw a 403 forbidden. I can even submit this form again with different information (which is desired behaviour) and still have success.
What concerns me is that after the first POST request, The console shows:
UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.'
The first time the template is rendered, it renders it using render(request, 'appname/index.html', context), which I understand should include the same information that RenderContext() provides in a more efficient method.
Does anybody have any idea about what might be going wrong?
My ajax code:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin URL
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
$(function(){
var csrftoken = $.cookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// Define ajax submit function
$('.tab-pane form').submit(function (event){
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
data: new FormData($('.tab-pane.active form').get(0)),
dataType: "json",
processData: false,
contentType: false,
success: function(data) {
// Re-enable submit button
$(".submit-btn").removeClass("disabled");
$(".cancel-btn").removeClass("disabled");
// Show errors or clean and reset form
$('.tab-pane.active form div:first').replaceWith(data['form_html']);
if (data['success']) {
// Close modal
$('#incidentForm').modal('hide');
// Add point to map
var point = geojsonMarker(JSON.parse(data['point']), data['point_type'])
point.bindPopup(getPopup(point.getLayers()[0]));
incidentData.addLayer(point);
// Pan to point
map.setView(point.getBounds().getCenter(), 18, {'animate': true});
setTimeout(function(){
point.openPopup();
}, 300);
// Print success or failure message
var message = "<strong>" + '{% trans "Thank you!" %}' + "</strong><br>" + '{% trans "Your incident marker was successfully added." %}';
showMessage(message);
}
}
});
event.preventDefault();
});
})
My view method is the following:
#require_POST
def postTheft(request):
return postPoint(request, TheftForm)
def postPoint(request, Form):
"""Submit a user point submission to the database. Normalize geometry and activate push notifications."""
form = Form(request.POST)
form.data = form.data.copy()
# Convert coords to valid geometry
try:
form.data['geom'] = normalizeGeometry(form.data['geom'])
except(ValueError):
messages.error(request, '<strong>' + _('Error') + '</strong><br>' + _('No point was selected for this type of report.'))
# Validate and submit to db
if form.is_valid():
point = form.save()
# Errors with push notifications should not affect reporting
if not settings.DEBUG:
try: pushNotification.pushNotification(point)
except: pass
return JsonResponse({
'success': True,
'point': GeoJSONSerializer().serialize([point,]),
'point_type': point.p_type,
'form_html': render_crispy_form(Form())
})
else:
logger.debug("Form not valid")
# Else: error occurred
form.data['geom'] = form.data['geom'].json
form_html = render_crispy_form(form)
return JsonResponse({'success': False, 'form_html': form_html})
Code that renders the initial template:
def index(request, lat=None, lng=None, zoom=None):
incidents = Incident.objects.select_related('point').all()
context = {
# Model data used by map
'collisions': incidents.filter(p_type__exact="collision"),
'nearmisses': incidents.filter(p_type__exact="nearmiss"),
'hazards': Hazard.objects.select_related('point').all(),
'thefts': Theft.objects.select_related('point').all(),
"geofences": AlertArea.objects.filter(user=request.user.id),
# Form data used by map
"incidentForm": IncidentForm(),
"geofenceForm": GeofenceForm(),
"hazardForm": HazardForm(),
"theftForm": TheftForm(),
"editForm": EditForm()
}
# Add zoom and center data if present
if not None in [lat, lng, zoom]:
context['lat']= float(lat)
context['lng']= float(lng)
context['zoom']= int(zoom)
return render(request, 'mapApp/index.html', context)
I messed up when disabling the csrf_tag in my django crispy_forms template. So, the csrf token was available as a header, but render_crispy_form was trying to render the csrf token even though it wasn't there when passed back from the JsonResponse.
Alasdair's comment pointed me in the right direction.
Thanks for the help everyone!

Django, Ajax- HttpResponse does not send json

Django 1.7.2/ python 3.4
this code is about 'like'.
if user click the 'like' button, ajax calls 'pushLike'.
if the user has liked the article before(saved inside Mysql), delete the row on table(DB).
or if the user is not liking the article, create a row and insert it on the table(DB).
after that, count how many like has beed clicked on that article.
I would like to pass the likeCnt(count) to ajax, and write it on the button.
The likeCnt has the right value(I checked it on the server mysql table).
The button color does change(white to blue, and vise versa), but the text does not change.
It seems like json does not pass to ajax. I tried passing data by 'text' type and it did worked, but i want it by json.
I've tried simplejson, json, mimetype, content_type on HttpResponse.
please help me.
view
#login_required
def pushLike(request):
pk = request.GET['writing_id']
try:
la = LikeArticles.objects.get(user = User.objects.get(username=request.user.username), article_id=pk)
if(la.is_like()):
la.delete()
likeCnt = LikeArticles.objects.filter(article_id=pk).count()
FreeBoards.objects.filter(id=pk).update(like = likeCnt)
else: #Never happens
la.like = True
la.save()
likeCnt = LikeArticles.objects.filter(article_id=pk).count()
FreeBoards.objects.filter(id=pk).update(like = likeCnt)
except ObjectDoesNotExist:
la = LikeArticles(user = User.objects.get(username=request.user.username),
article = FreeBoards.objects.get(id=pk),
like = True,
)
la.save()
likeCnt = LikeArticles.objects.filter(article_id=pk).count()
FreeBoards.objects.filter(id=pk).update(like = likeCnt)
data = {'likeCnt': likeCnt}
# return render(request, url, context)
return HttpResponse(simplejson.dumps(data), mimetype='application/javascript')
javascript
<script type="text/javascript">
$(document).ready(function(){
$('#btn-like').click(function(){
var e = $('#btn-like').css('background-color');
$.ajax({
url : '/sle/freeboards/pushLike/',
data : {'writing_id':{{writing_id}},
},
dataType : "json",
success:function(data){
alert(data.likeCnt);
if(e == 'rgb(59, 89, 152)') {
$('#btn-like').css('background-color', '#ffffff').css('color', '#000000');
$('#btn-like').text(data.likeCnt);
} else {
$('#btn-like').css('background-color', '#3b5998').css('color', '#ffffff');
$('#btn-like').text(data.likeCnt);
}
},
failure: function(data){
alert('fail!!')
}
});
});
});
</script>
you'll want to be sure to set the proper mimetype in your HttpResponse
#login_required
def pushLike(request):
...
# return json -- !!not javascript!!
return HttpResponse(simplejson.dumps(...), mimetype="application/json")
--or--
#login_required
def pushLike(request):
...
# return json -- !!not javascript!!
return JsonResponse({"your": "context dictionary"})
If that doesn't work, have you tried parsing the json with your Jquery code?
ie:
$.ajax({
...
success: function(data){
var response = $.parseJSON(data);
...
}
});
javascript might actually receiving bytes back from whatever you are serving your django app with... so instead of getting JSON back, you're actually getting string that looks like JSON. http://api.jquery.com/jquery.parsejson/

Resources