5

I'm learning Backbone.js and Flask (and Flask-sqlalchemy). I chose Flask because I read that it plays well with Backbone implementing RESTful interfaces. I'm currently following a course that uses (more or less) this model:

class Tasks(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(80), unique=True)
    completed = db.Column(db.Boolean, unique=False, default=False)

    def __init__(self, title, completed):
        self.title = title
        self.completed = completed

    def json_dump(self):
        return dict(title=self.title, completed=self.completed)

    def __repr__(self):
        return '<Task %r>' % self.title

I had to add a json_dump method in order to send JSON to the browser. Otherwise, I would get errors like object is not JSON serializable, so my first question is:

Is there a better way to do serialization in Flask? It seems that some objects are serializable but others aren't, but in general, it's not as easy as I expected.

After a while, I ended up with the following views to take care of each type of request:

@app.route('/tasks')
def tasks():
    tasks = Tasks.query.all()
    serialized = json.dumps([c.json_dump() for c in tasks])
    return serialized

@app.route('/tasks/<id>', methods=['GET'])
def get_task(id):
    tasks = Tasks.query.get(int(id))
    serialized = json.dumps(tasks.json_dump())
    return serialized

@app.route('/tasks/<id>', methods=['PUT'])
def put_task(id):
    task = Tasks.query.get(int(id))
    task.title = request.json['title']
    task.completed = request.json['completed']
    db.session.add(task)
    db.session.commit()
    serialized = json.dumps(task.json_dump())
    return serialized

@app.route('/tasks/<id>', methods=['DELETE'])
def delete_task(id):
    task = Tasks.query.get(int(id))
    db.session.delete(task)
    db.session.commit()
    serialized = json.dumps(task.json_dump())
    return serialized

@app.route('/tasks', methods=['POST'])
def post_task():
    task = Tasks(request.json['title'], request.json['completed'])
    db.session.add(task)
    db.session.commit()
    serialized = json.dumps(task.json_dump())
    return serialized

In my opinion, it seems a bit verbose. Again, what is the proper way to implement them? I have seen some extensions that offer RESTful interfaces in Flask but those look quite complex to me.

Thanks

r_31415
  • 8,752
  • 17
  • 74
  • 121

2 Answers2

8

I would use a module to do this, honestly. We've used Flask-Restless for some APIs, you might take a look at that:

https://flask-restless.readthedocs.org/en/latest/

However, if you want build your own, you can use SQLAlchemy's introspection to output your objects as key/value pairs.

http://docs.sqlalchemy.org/en/rel_0_7/core/schema.html#metadata-reflection

Something like this, although I always have to triple-check I got the syntax right, so take this as a guide more than working code.

@app.route('/tasks')
def tasks():
    tasks = Tasks.query.all()

    output = []
    for task in tasks:
      row = {}

      for field in Tasks.__table__.c:
        row[str(field)] = getattr(task, field, None)

      output.append(row)

    return jsonify(data=output)

I found this question which might help you more. I'm familiar with SQLAlchemy 0.7 and it looks like 0.8 added some nicer introspection techniques:

SQLAlchemy introspection

Community
  • 1
  • 1
Rachel Sanders
  • 5,734
  • 1
  • 27
  • 36
  • Sorry for the late response. Yes, I think the project you reference is the same that I had in mind. By the way, I'm using flask-sqlalchemy so I don't know what to make of sqlalchemy's introspection. I guess I could use the first option, but I was expecting something else. – r_31415 Nov 28 '12 at 19:23
  • It's definitely not for the squeamish, but it's powerful. And you can use this method with Flask-SQLAlchemy, in fact, the example I gave there uses Flask-SQLAlchemy. I've used it in our app to do custom data extraction and other deep magic. – Rachel Sanders Nov 28 '12 at 21:51
  • Good, I will try to implement it. Do you know if these baked-in approaches are doing something besides managing requests and setting routes or basically that's all there is to it. – r_31415 Nov 29 '12 at 02:42
  • For an example of using introspection to serialize models: https://wakatime.com/blog/32-part-1-sqlalchemy-models-to-json – Alan Hamlett Jul 11 '18 at 22:48
-1

Flask provides jsonify function to do this. Check out its working here.

Your json_dump method is right though code can be made concise. See this code snippet

@app.route('/tasks')
def tasks():
    tasks = Tasks.query.all()
    return jsonify(data=[c.json_dump() for c in tasks])
codecool
  • 5,886
  • 4
  • 29
  • 40
  • But only for some objects. It doesn't work "out of the box" in this case. See this http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask. The proposed solutions are far too complicated. – r_31415 Nov 24 '12 at 19:52