sql_todo.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!/bin/env python
  2. from flask import Flask, request
  3. from flask_restful import reqparse, abort, Api, Resource
  4. from flask_httpauth import HTTPBasicAuth
  5. from flask_sqlalchemy import SQLAlchemy
  6. import json
  7. # This "protects" paths with @auth.login_required
  8. auth = HTTPBasicAuth()
  9. # This is a very basic (and dumb) security model
  10. # We'll actually want the @auth.verify_password model,
  11. # which will let us use hashed passwords, etc.
  12. @auth.get_password
  13. def get_password(username):
  14. if username == 'admin':
  15. return '12345'
  16. return None
  17. @auth.error_handler
  18. def unauthorized():
  19. return abort(401, message='Unauthorized access')
  20. app = Flask(__name__)
  21. app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
  22. app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  23. app.config['RESTFUL_JSON'] = { 'separators': ( ', ', ': '), 'indent': 2 }
  24. db = SQLAlchemy(app)
  25. api = Api(app)
  26. class Todo(db.Model):
  27. id = db.Column(db.Integer, primary_key=True)
  28. name = db.Column(db.String(20), unique=True, nullable=False)
  29. detail = db.Column(db.String(200), unique=False, nullable=False)
  30. def __repr__(self):
  31. return '<Todo {0}: {1}'.format(self.id, self.name)
  32. def serialize(self):
  33. return {'id': self.id, 'name': self.name, 'detail': self.detail}
  34. def abort_if_todo_doesnt_exist(todo_id):
  35. task = Todo.query.filter_by(id=todo_id).first()
  36. if task is None:
  37. abort(404, message="Todo {} doesn't exist".format(todo_id))
  38. return task
  39. # if todo_id not in TODOS:
  40. # abort(404, message="Todo {} doesn't exist".format(todo_id))
  41. parser = reqparse.RequestParser()
  42. # http://flask-restful.readthedocs.io/en/0.3.5/reqparse.html
  43. parser.add_argument('task', required=True)
  44. parser.add_argument('name', required=True)
  45. # Todo
  46. # shows a single todo item and lets you delete a todo item
  47. # Yes! You can add the @auth.login_required to methods of the class. ! \o/ !
  48. class TodoPath(Resource):
  49. def get(self, todo_id):
  50. t = abort_if_todo_doesnt_exist(todo_id)
  51. return { 'id': t.id, 'name': t.name, 'detail': t.detail }
  52. def delete(self, todo_id):
  53. t = abort_if_todo_doesnt_exist(todo_id)
  54. db.session.delete(t)
  55. db.session.commit()
  56. return '', 204
  57. # @auth.login_required
  58. def put(self, todo_id):
  59. args = parser.parse_args()
  60. t = args['task']
  61. if t is None:
  62. abort(400, message="I need text for the task. task=...")
  63. task = Todo(name=todo_id, detail=t)
  64. db.session.add(task)
  65. db.session.commit()
  66. return task.id, 201
  67. # TodoList
  68. # shows a list of all todos, and lets you POST to add new tasks
  69. class TodoList(Resource):
  70. def get(self):
  71. tasks = Todo.query.all()
  72. return [t.serialize() for t in tasks]
  73. def post(self):
  74. args = parser.parse_args()
  75. # This doesn't check to see if name already exists in the database.
  76. task = Todo(name=args['name'], detail=args['task'])
  77. db.session.add(task)
  78. db.session.commit()
  79. return task.id, 201
  80. # @auth.login_required
  81. class Hello(Resource):
  82. @auth.login_required
  83. def get(self):
  84. return { 'Working': True, 'headers': dict(request.headers) }
  85. ##
  86. ## Actually setup the Api resource routing here
  87. ##
  88. api.add_resource(TodoList, '/todos', '/todos/')
  89. # api.add_resource(TodoList, '/todos/')
  90. api.add_resource(TodoPath, '/todos/<todo_id>')
  91. api.add_resource(Hello, '/')
  92. if __name__ == '__main__':
  93. app.run(port=11022, debug=True)