6

(This is probably a dumb question, so please wear your stupidity shields!) I've been a PHP programmer and am now learning Python + Flask. I recently had to struggle a lot with posting data through AJAX and returning a response. Finally, the code that worked was:

@app.route('/save', methods=['POST'])
def save_subscriptions():
    if request.method == 'POST':
        sites = request.form.get('selected')
        print(sites)
        sites = sites[0:-1]        
        g.cursor.execute('UPDATE users SET sites = %s WHERE email = %s', [sites, session.get('email')])
        g.db.commit()
        return json.dumps({'status': 'success'})

If I change return json.dumps({'status': 'success'}) to return 1 I get an Exception that int is not callable. First of all, I don't understand who is trying to call that int and why? Secondly, in PHP, it was frequently possible to just echo 1; and this would become the AJAX response. Why doesn't return 1 work in Flask, then?

ankush981
  • 5,159
  • 8
  • 51
  • 96
  • 2
    Please sanitize your SQL queries! – Will Sherwood Dec 26 '15 at 04:06
  • @WillSherwood Thanks! I was wondering yesterday what was the equivalent of PHP's prepared statements but didn't give it much thought as it is a personal project. I'll change this pronto! – ankush981 Dec 26 '15 at 04:10
  • @WillSherwood Hey, wait a minute! I look at http://bobby-tables.com/python.html and wondering whether my queries aren't already sanitized. What else do I need to to? – ankush981 Dec 26 '15 at 04:12
  • 1
    @dotslash nono, you are doing it correctly, since you parameterize queries. – alecxe Dec 26 '15 at 04:37

1 Answers1

8

The logic behind what should be returned by Flask views is described in the docs in detail:

The return value from a view function is automatically converted into a response object for you. If the return value is a string it’s converted into a response object with the string as response body, an 200 OK error code and a text/html mimetype. The logic that Flask applies to converting return values into response objects is as follows:

  • If a response object of the correct type is returned it’s directly returned from the view.

  • If it’s a string, a response object is created with that data and the default parameters.

  • If a tuple is returned the items in the tuple can provide extra information. Such tuples have to be in the form (response, status, headers) where at least one item has to be in the tuple. The status value will override the status code and headers can be a list or dictionary of additional header values.

  • If none of that works, Flask will assume the return value is a valid WSGI application and convert that into a response object.

In your case, integer 1 is returned - Flask applies the last rule and tries to convert it into a response object and fails. Internally, make_response() method is called which, in case of an integer, would call force_type() method of a werkzeug.Response class which would eventually fail creating an instance of a BaseResponse class when trying to instantiate a WSGI app:

app_rv = app(environ, start_response)

where app in your case is integer 1.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • Ah, silly me! So all I had to do was `return "1"`. Thanks! Will accept this as my answer as soon the site allows me. – ankush981 Dec 26 '15 at 03:51
  • And thanks for the full explanation. Makes me see web frameworks in a totally different light. :-) – ankush981 Dec 26 '15 at 04:03