Browse Source

Updated with SQLAlchemy example sqlite.

Charlie Root 7 years ago
parent
commit
660b52a133
6 changed files with 145 additions and 0 deletions
  1. 22 0
      FROM.txt
  2. 8 0
      full_todo.py
  3. BIN
      oursql-0.9.4.zip
  4. 2 0
      requirements.txt
  5. 113 0
      sql_todo.py
  6. BIN
      todo.db

+ 22 - 0
FROM.txt

@@ -2,3 +2,25 @@
 See:
 http://flask-restful.readthedocs.io/en/0.3.5/quickstart.html
 
+
+
+Using httpauth:
+https://blog.miguelgrinberg.com/post/restful-authentication-with-flask
+
+Using SQLAlchemy and Flask:
+http://flask-sqlalchemy.pocoo.org/2.3/quickstart/
+
+
+# Because of a bug in oursql, I need to download and install manually...
+
+wget https://launchpad.net/oursql/py3k/py3k-0.9.4/+download/oursql-0.9.4.zip
+
+pip install oursql-0.9.4.zip 
+
+sql_todo init:
+
+python
+import sql_todo
+
+sql_todo.db.create_all()
+

+ 8 - 0
full_todo.py

@@ -4,8 +4,13 @@ from flask import Flask
 from flask_restful import reqparse, abort, Api, Resource
 from flask_httpauth import HTTPBasicAuth
 
+# This "protects" paths with @auth.login_required
 auth = HTTPBasicAuth()
 
+# This is a very basic (and dumb) security model
+# We'll actually want the @auth.verify_password model,
+# which will let us use hashed passwords, etc.
+
 @auth.get_password
 def get_password(username):
     if username == 'admin':
@@ -37,6 +42,9 @@ parser.add_argument('task')
 
 # Todo
 # shows a single todo item and lets you delete a todo item
+
+# Yes!  You can add the @auth.login_required to methods of the class.  ! \o/ !
+
 class Todo(Resource):
     def get(self, todo_id):
         abort_if_todo_doesnt_exist(todo_id)

BIN
oursql-0.9.4.zip


+ 2 - 0
requirements.txt

@@ -3,6 +3,7 @@ click==6.7
 Flask==0.12.2
 Flask-HTTPAuth==3.2.3
 Flask-RESTful==0.3.6
+Flask-SQLAlchemy==2.3.2
 gunicorn==19.7.1
 itsdangerous==0.24
 Jinja2==2.10
@@ -11,4 +12,5 @@ python-dateutil==2.6.1
 pytz==2017.3
 setproctitle==1.1.10
 six==1.11.0
+SQLAlchemy==1.1.15
 Werkzeug==0.12.2

+ 113 - 0
sql_todo.py

@@ -0,0 +1,113 @@
+#!/bin/env python
+
+from flask import Flask
+from flask_restful import reqparse, abort, Api, Resource
+from flask_httpauth import HTTPBasicAuth
+from flask_sqlalchemy import SQLAlchemy
+import json
+
+# This "protects" paths with @auth.login_required
+auth = HTTPBasicAuth()
+
+# This is a very basic (and dumb) security model
+# We'll actually want the @auth.verify_password model,
+# which will let us use hashed passwords, etc.
+
[email protected]_password
+def get_password(username):
+    if username == 'admin':
+        return '12345'
+    return None
+
[email protected]_handler
+def unauthorized():
+    return abort(401, message='Unauthorized access')
+
+
+app = Flask(__name__)
+app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
+db = SQLAlchemy(app)
+api = Api(app)
+
+class Todo(db.Model):
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String(20), unique=True, nullable=False)
+    detail = db.Column(db.String(200), unique=False, nullable=False)
+
+    def __repr__(self):
+        return '<Todo {0}: {1}'.format(self.id, self.name)
+
+    def serialize(self):
+        return {'id': self.id, 'name': self.name, 'detail': self.detail}
+
+TODOS = {
+    'todo1': {'task': 'build an API'},
+    'todo2': {'task': '?????'},
+    'todo3': {'task': 'profit!'},
+}
+
+
+def abort_if_todo_doesnt_exist(todo_id):
+    task = Todo.query.filter_by(id=todo_id).first()
+    if task is None:
+        abort(404, message="Todo {} doesn't exist".format(todo_id))
+    return task
+
+    # if todo_id not in TODOS:
+    #    abort(404, message="Todo {} doesn't exist".format(todo_id))
+
+parser = reqparse.RequestParser()
+parser.add_argument('task')
+
+
+# Todo
+# shows a single todo item and lets you delete a todo item
+
+# Yes!  You can add the @auth.login_required to methods of the class.  ! \o/ !
+
+class TodoPath(Resource):
+    def get(self, todo_id):
+        t = abort_if_todo_doesnt_exist(todo_id)
+        return { 'id': t.id, 'name': t.name, 'detail': t.detail }
+
+    def delete(self, todo_id):
+        abort_if_todo_doesnt_exist(todo_id)
+        del TODOS[todo_id]
+        return '', 204
+
+    # @auth.login_required
+    def put(self, todo_id):
+        args = parser.parse_args()
+        t = args['task']
+        if t is None:
+            abort(400, message="I need text for the task. task=...")
+        task = Todo(name=todo_id, detail=t)
+        db.session.add(task)
+        db.session.commit()
+        return task.id, 201
+
+
+# TodoList
+# shows a list of all todos, and lets you POST to add new tasks
+class TodoList(Resource):
+    def get(self):
+        tasks = Todo.query.all()
+        return [t.serialize() for t in tasks]
+        # return TODOS
+
+    def post(self):
+        args = parser.parse_args()
+        todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1
+        todo_id = 'todo%i' % todo_id
+        TODOS[todo_id] = {'task': args['task']}
+        return TODOS[todo_id], 201
+
+##
+## Actually setup the Api resource routing here
+##
+api.add_resource(TodoList, '/todos')
+api.add_resource(TodoPath, '/todos/<todo_id>')
+
+
+if __name__ == '__main__':
+    app.run(port=11022, debug=True)

BIN
todo.db