In a template I have the following code.
<script>
var url="/mypjt/my_timer"
$.post(url, paramarr,
function callbackHandler(dict)
{
alert('got response back');
if (dict.flag == 2)
{
alert('1');
$.jGrowl("Data could not be saved");
}
else if(dict.ret_status == 1)
{
alert('2');
$.jGrowl("Data saved successfully");
window.location = "/mypjt/display/" + dict.rid;
}
},
"json"
);
</script>
In views I have the following code,
def my_timer(request):
dict={}
try:
a = timer.objects.get(pk=1)
dict({'flag':1})
return HttpResponse(simplejson.dumps(dict), mimetype='application/javascript')
except:
dict({'flag':1})
return HttpResponse(simplejson.dumps(dict), mimetype='application/javascript')
Since we are making a JSON request and in the try block, after setting the flag, can't we return a page directly as
return render_to_response('mypjt/display.html',context_instance=RequestContext(request,{'dict': dict}))
instead of sending the response, because on success again in the HTML page we redirect the code?
Also if there is a exception then only can we return the JSON request.
My only concern is that the interaction between client and server should be minimal.
If you do the response like you said,
return
render_to_response('mypjt/display.html',context_instance=RequestContext(request,{'dict':
dict}))
the JavaScript code will receive your response, not the navigator. I think you can do somethink like this:
<script>
$(document).ready(function()
{
$('#yourForm').submit();
});
</script>
<form id="yourForm" action="/mypjt/my_timer" method="post">
...
your fields with data, even they are hidden
...
</form>
So, in Django you can do the response like you said:
def my_timer(request):
dict={}
try:
a= timer.objects.get(pk=1)
dict({'flag':1})
return render_to_response('mypjt/display.html',context_instance=RequestContext(request,{'dict': dict}))
except:
dict({'flag':0})
return render_to_response('mypjt/error_not_found.html',context_instance=RequestContext(request,{'dict': dict}))
Or, you can do like you were doing but if the query "timer.objects.get(pk=1)" fails, for example, you send back a boolean flag response. So, when it is OK you redirect to the page you prefer.
I hope it could be useful to you!
If I understand rightly, you're sniffing the return code in the JavaScript, and then redirecting depending on the results.
You can do a redirect from Django, so I would do that instead of worrying about return codes. When you've got both a "flag" and a "ret_status", that is a hint you should re-think your design. :)
Also, shadowing the built-in dict object in the Python code should be avoided.
Related
I'm a beginner.
What I used was flask and pymongo.
If you press the button, it's "Like". It should be +1, but there is a key error at the bottom.
My python route code:
#app.route('/api/like', methods=['POST'])
def like_movie():
title_receive = request.form['title_give']
movie = db.toytoy.find_one({'title': title_receive})
current_like = movie['like']
new_like = current_like + 1
db.toytoy.update_one({'title': title_receive}, {'$set': {'like': new_like}})
return jsonify({'msg': 'like!'})
This is how I POST from JS
function like_movie(title) {
$.ajax({
type: 'POST',
url: '/api/like',
data: {title_give: title},
success: function (response) {
console.log(response)
alert(response['msg']);
window.location.reload();
}
});
}
I get an exception as below:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'title_give'
What I want is if it's 'like_btn'. If you press the button, it becomes +1.
The base problem in what you did is not respecting Content-type. From front JS, you are making a POST with JSON object. Which makes the request to have a content type of application/json.
In backend code, you use request.form which expects the request to be in the form encoded types (like application/x-www-form-urlencoded, multipart/form-data) etc.
So, you need to read the JSON content in backend, instead of reading from a form which is not available. Like below:
ui_req = request.get_json()
title_receive = ui_req['title_give']
And then parse other structures accordingly.
So I have been going at this for hours. Usually this works out for me so I decided to ask for some help. My Http Post from AngularJS:
$scope.receipt_pay_update = function(){
response = confirm("Do you want to continue with the changes?")
if(!response){
return;
}
var data = {
'items': "ABC",
}
console.log($scope.current_farmer)
$http.post('/foodhub/dashboard/receipt_pay_modal_update',data, {data: JSON}
)}
Here is my views.py for the request:
def receipt_pay_modal_update(request):
import sys
reload(sys)
sys.setdefaultencoding('utf8')
print "#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$"
print request
print "#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$"
print request.GET
I am trying to get that "ABC" but it keeps showing empty. Here is my logs:
#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$
<WSGIRequest: GET '/foodhub/dashboard/receipt_pay_modal_update/'>
#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$#$$$$##$$$
<QueryDict: {}>
This usually works for me so I have no idea what is happening.
EDIT: So even though I am doing a POST I keep getting GET in the request body
I am reviewing this repository https://github.com/ibrahim4529/flask-chatbot to get an inspiration and see how a model can be deployed in a chat UI. I am able to do this in Flask but ran across a quirky situation that I am not sure how to resolve. The UI accepts the first initial message that I type, but when I try returning the response, I get an 'undefined' appended to every line that is supposed to be the bot's response. On CMD though, my function is returning response. I've provided screenshots below:
Here is my routing:
#app.route('/')
def hello():
return render_template('index.html')
#app.route('/ask', methods={'POST', 'GET'})
def ask():
if request.method == 'POST':
message = (request.form['messageText'])
bresponse = response(message)
return render_template('Index.html', bresponse=bresponse)
'response' is a function that spits out the response of the model (this is the 'Rrraawwwwg!' response from the input).
Below is the js that I reviewed from the link that I am using:
$('#chatbot-form').submit(function(e) {
e.preventDefault();
var message = $('#messageText').val();
$(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div style = "text-align:right; color : #2EFE2E" class="media-body">' + message + '<hr/></div></div></div></li>');
$.ajax({
type: "POST",
url: "/ask",
data: $(this).serialize(),
success: function(response) {
//console.log(response);
$('#messageText').val('');
var answers = response.answers;
const chatPanel = document.getElementById("chatPanel");
$(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div style = "color : white" class="media-body">' + answers + '<hr/></div></div></div></li>');
$(".fixed-panel").stop().animate({ scrollTop: $(".fixed-panel")[0].scrollHeight}, 1000);
I am not sure what I am missing. I am seeing the response in the cli, but seeing an undefined in the UI.
Thanks in advance!
I finally was able to make this work. I've updated ajax to below:
var answers = response;
$('#messageText').val();
I was also printing the response function, instead of returning it; reason I am seeing the response in the console and not in the view. This was the main culprit.
I want to create a Flask error handler that returns a JSON response if the request was from JavaScript but returns a redirect otherwise. I tried using request.is_xhr, but it is false even for JavaScript requests. How can I check if the request is from JavaScript?
#app.errorhandler(Exception)
def unhandled_exception(error):
if request.is_xhr:
return flask.jsonify(error='yes')
return redirect(url_for('error'))
There is no standard or reliable way to detect if a request comes from a particular source, such as JavaScript.
is_xhr was only true when a certain header was set by some JavaScript libraries, such as jQuery. The header is not sent by most JavaScript. is_xhr has been deprecated for that reason.
You can check the Accept header to see if the client is asking for application/json, but that too is unreliable.
if request.is_xhr or request.accept_mimetypes.accept_json:
return jsonify(...)
return redirect(...)
Answer by #davidism makes sense. is_xhr was only true when a certain header was set by some JavaScript libraries. So, I have set header 'X-Requested-With' to 'XMLHttpRequest' manually in '$httpProvider' config in AngularJs. This ensures that on the back end I will get 'is_xhr' true for AJAX request.
app.config([
'$httpProvider',
function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
var interceptor = [
'$q',
'$rootScope',
function ($q, $rootScope) {
'responseError': function (rejection) {
if(rejection.status != undefined && rejection.status != 'undefined') {
window.location.href = '/error';
}
}
};
return service;
}
];
$httpProvider.interceptors.push(interceptor);
}
]);
Rather than tie my app to a non-standard header I added an Accept: header to my Javascript instead:
let req = new XMLHttpRequest();
req.open('POST', location);
// signal back-end to return json instead of rendering a full page:
req.setRequestHeader('Accept', 'application/json');
req.send(…);
And in my Python:
# if an ajax-like request, return json instead of html
if request.accept_mimetypes.best == 'application/json':
log.debug('client prefers json, skipping page render.')
return jsonify(status='errror', detail='…')
This should handle other use cases as they come up.
If the request is from a javascript/jquery code, is it most certainly from a browser so you can check the flask.request.user_agent object which is a instance of werkzeug.useragents.UserAgent to verify that.
I'm trying to allow the click trigger to do some backend dynamic csv creation, and then return it back to the user as a csv download file. I guess I'm not sure how I should write out the return statement other than just putting return response. I'v come across some other posts saying that I would need to set my url to a hidden iframe?? Not sure what this means though. Any tips?
Ajax looks like this:
$('#download-maxes').on('click', function(){
$.ajax({
type: "POST",
url: "{{request.path}}download/",
dataType: 'json',
async: false,
data: JSON.stringify(workouts),
success: function(workoutData) {
console.log(workoutData);
},
error:function(error){
console.log(error);
}
});
});
And my django view looks like this:
def download(request):
#(... a lot of mongo stuff here & other things defined)
workouts = json.load(request.body)
response = HttpResponse(content_type='text/xlsx')
response['Content-Disposition'] = 'attachment; filename="team_maxes.xlsx"'
writer = csv.writer(response)
writer.writerow(['Name', 'Date', 'Workout', 'Max'])
for member in team_members.all():
for wo in workouts:
wo_data = db.activity_types.find_one({"name": wo["name"]})
best_wo = db.activity.find_one({"u_id": member.user.id, "a_t": str(wo_data["_id"]), "is_last": 1}) or 0
member_name = member.user.first_name + ' ' + member.user.last_name
try:
max_stat = best_wo["y_ts"]
except:
max_stat = 0
try:
date = best_wo["e_d"]
except:
date = ""
workout_name = wo_data["name"]
writer.writerow([member_name, date, workout_name, max_stat])
return response
You don't need to use ajax. Since you are POSTing some json data to your view, just make a form with a hidden text input, and set it's value to the json data. Then make a regular submit button in the form.
When the form gets submitted, and the server responds with Content-Disposition: attachment; filename="team_maxes.xlsx", your browser will automatically trigger a download.
If you decide to go this route, Keep in mind:
You are using a regular html form now, with the POST method, so you must remember to use django's {% csrf_token %} tag inside of it.
You will probably have set the input's value to your json string, right before submitting the form.
Your workouts json gets sent in a form input. So, assuming you named your input "workouts", in your view you would do something like:
workouts = json.loads(request.POST.get('workouts'))
Plus a bunch of error checking, of course.