I'm trying to post the following JSON and save to a MySQL database on a Flask server and Python 2.7, restless framework and SQLAlchemy with curl:
curl -i -H "Accept: application/json" -X POST -d '{"attribute_id": "1", "product_id": "44","text":"Something","language":"1"}' http://seroney-pc:5000/api/attributes
{
"attribute_id": "1",
"product_id": "44",
"text": "Something",
"language": "1"
}
My code is as follows:
from flask import Flask,request,jsonify, abort
from flask_sqlalchemy import SQLAlchemy
import flask_restless
app = Flask(__name__)
db = SQLAlchemy(app)
manager = flask_restless.APIManager(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:seroney@localhost:3306/test'
class Attributes(db.Model):
__tablename__ = 'oc_product_attribute'
product_id = db.Column(db.Integer,primary_key=True)
attribute_id = db.Column(db.Integer,primary_key=True)
language_id = db.Column(db.Integer,primary_key=True)
text=db.Column(db.String)
@app.route('/api/attributes/',methods=['GET'])
def getProductAttributes():
if request.method =='GET':
results = Attributes.query.limit(10).offset(0).all()
json_results = []
for result in results:
d = {
'product_id':result.product_id,
'attribute_id':result.attribute_id,
'language_id':result.language_id,
'text':result.text
}
json_results.append(d)
return jsonify(items = json_results)
@app.route('/api/attributes/', methods=['POST'])
def postProductAttributes():
product_id = request.json['product_id']
attribute_id = request.json['attribute_id']
language_id = request.json['language_id']
text = request.json['text']
if product_id is None or attribute_id is None or language_id is None or text is None:
return jsonify({"message": "Error."}), 400
new_attrib = (product_id,attribute_id,language_id,text)
db.session.add(new_attrib)
db.session.commit()
return jsonify({'message' :'Attribute Created successfully'}), 200
if __name__ == '__main__':
app.run(debug=True)
When I POST I keep I getting an Internal Server Error. Any help is highly appreciated.
The traceback is:
seroney-pc - - [23/Dec/2014 20:48:40] "POST /api/attributes HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1453, in dispatch_request
self.raise_routing_exception(req)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1439, in raise_routing_exception
raise FormDataRoutingRedirect(request)
Note: this exception is only raised in debug mode
You are posting to the URL without a
/
at the end, but you specified your route with a trailing/
. When you do that, Flask issues a redirect to the 'canonical' URL, with the/
.Because you are using POST, the post data will be lost, so in debug mode an exception is raised instead to inform you that you should use the trailing slash in your post instead.
Had you looked at the body of the error message, you'd have seen something like:
See the Rule Format documentation:
Note that your
curl
POST uses the wrong header; you need to set the Content-Type header. Your view is looking for thelanguage_id
key, but your post contains only alanguage
key, you need to correct that too:The
Accept
header may be useful too, but it is used for negotiating the response content type, and you have your views hardcoded to return JSON.Your code creating the database object is also incorrect, you need to call the model and pass in the arguments as separate arguments, then pass in the resulting to
session.add()
:but just reusing the JSON object would be easier here: