[Python] Flask 基本教學

程式語言:Python
Package:
flask
flask_script
flask_sqlalchemy
flask_admin
flask_login
Flask 官方網站
GitHub

功能:架站

最簡易的程式碼
  1. # hello.py
  2. from flask import Flask
  3. app = Flask(__name__)
  4.  
  5. @app.route('/')
  6. def hello_world():
  7. return 'Hello, World!'
運行方法
# linux
#export FLASK_APP=hello.py
# window
set FLASK_APP=hello.py
python -m flask run

Flask-Script
提供外部指令,例:python manage.py runserver --debug
  1. # hello.py
  2. from flask import Flask
  3. app = Flask(__name__)
  4.  
  5. @app.route('/')
  6. def hello_world():
  7. return 'Hello, World!'
  1. # manage.py
  2. from flask_script import Manager
  3. from hello import app
  4.  
  5. manager = Manager(app)
  6.  
  7. # 自定指令
  8. @manager.command
  9. def hello():
  10. """Print hello"""
  11. print("hello")
  12.  
  13. if __name__ == "__main__":
  14. manager.run()
運行方法
# 可確認有哪些指令,自定的指令也會出現
python manage.py

# 運行 server
python manage.py runserver

# 運行 server 並啟動 debug,可輸入 pin 直接 debug
python manage.py runserver --debug

# 運行 shell
python manage.py shell

Flask-SQLAlchemy
ORM 工具,可直接用 python 控制資料庫
  1. # hello.py
  2. from flask import Flask
  3. app = Flask(__name__)
  4.  
  5. @app.route('/')
  6. def hello_world():
  7. return 'Hello, World!'
  8. # -------------- new -----------------
  9. from flask_sqlalchemy import SQLAlchemy
  10.  
  11. # 指定資料庫位置
  12. db_uri = 'sqlite:///{}'.format('app.db')
  13. app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
  14. db = SQLAlchemy(app)
  15.  
  16. class User(db.Model):
  17. id = db.Column(db.Integer, primary_key=True)
  18. username = db.Column(db.String(80), unique=True, nullable=False)
  19. email = db.Column(db.String(120), unique=True, nullable=False)
  20.  
  21. def __repr__(self):
  22. return '<User %r>' % self.username
  23.  
  24. @app.route('/db_demo')
  25. def db_demo():
  26. admin = User(username='admin', email='admin@example.com')
  27. guest = User(username='guest', email='guest@example.com')
  28. db.session.add(admin)
  29. db.session.add(guest)
  30. db.session.commit()
  31. return User.query.filter_by(username='admin').first().username
  32. # -------------- new -----------------
  1. # manage.py
  2. from flask_script import Manager
  3. from hello import app
  4.  
  5. manager = Manager(app)
  6.  
  7. @manager.command
  8. def hello():
  9. """Print hello"""
  10. print("hello")
  11.  
  12. # -------------- new -----------------
  13. from hello import db
  14.  
  15. @manager.command
  16. def initDB():
  17. """Initializes the database."""
  18. db.create_all(bind=None)
  19. # -------------- new -----------------
  20. if __name__ == "__main__":
  21. manager.run()
運行方法
# 建立資料庫
python manage.py initDB

# demo 網址為:http://127.0.0.1:5000/db_demo
python manage.py runserver

Flask-Admin
管理資料庫介面
  1. # hello.py
  2. from flask import Flask
  3. app = Flask(__name__)
  4.  
  5. @app.route('/')
  6. def hello_world():
  7. return 'Hello, World!'
  8. from flask_sqlalchemy import SQLAlchemy
  9.  
  10. # 指定資料庫位置
  11. db_uri = 'sqlite:///{}'.format('app.db')
  12. app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
  13. db = SQLAlchemy(app)
  14.  
  15. class User(db.Model):
  16. id = db.Column(db.Integer, primary_key=True)
  17. username = db.Column(db.String(80), nullable=False)
  18. email = db.Column(db.String(120), nullable=False)
  19.  
  20. def __repr__(self):
  21. return '<User %r>' % self.username
  22. @app.route('/db_demo')
  23. def db_demo():
  24. admin = User(username='admin', email='admin@example.com')
  25. guest = User(username='guest', email='guest@example.com')
  26. db.session.add(admin)
  27. db.session.add(guest)
  28. db.session.commit()
  29. return User.query.filter_by(username='admin').first().username
  30. # -------------- new -----------------
  31. from flask_admin import Admin
  32. from flask_admin.contrib.sqla import ModelView
  33.  
  34. admin = Admin(app, name='microblog', template_mode='bootstrap3')
  35. admin.add_view(ModelView(User, db.session))
  36. # -------------- new -----------------
  1. # manage.py
  2. from flask_script import Manager
  3. from hello import app
  4.  
  5. manager = Manager(app)
  6.  
  7. @manager.command
  8. def hello():
  9. """Print hello"""
  10. print("hello")
  11.  
  12. from hello import db
  13.  
  14. @manager.command
  15. def initDB():
  16. """Initializes the database."""
  17. db.create_all(bind=None)
  18. if __name__ == "__main__":
  19. manager.run()
運行方法
# 介面網址為:http://127.0.0.1:5000/admin/
python manage.py runserver

Flask-Login
提供使用者登入驗證相關工具
  1. # hello.py
  2. from flask import Flask
  3. app = Flask(__name__)
  4.  
  5. @app.route('/')
  6. def hello_world():
  7. return 'Hello, World!'
  8. from flask_sqlalchemy import SQLAlchemy
  9.  
  10. # 指定資料庫位置
  11. db_uri = 'sqlite:///{}'.format('app.db')
  12. app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
  13. db = SQLAlchemy(app)
  14.  
  15. class User(db.Model):
  16. id = db.Column(db.Integer, primary_key=True)
  17. username = db.Column(db.String(80), nullable=False)
  18. email = db.Column(db.String(120), nullable=False)
  19.  
  20. def __repr__(self):
  21. return '<User %r>' % self.username
  22. @app.route('/db_demo')
  23. def db_demo():
  24. admin = User(username='admin', email='admin@example.com')
  25. guest = User(username='guest', email='guest@example.com')
  26. db.session.add(admin)
  27. db.session.add(guest)
  28. db.session.commit()
  29. return User.query.filter_by(username='admin').first().username
  30. from flask_admin import Admin
  31. from flask_admin.contrib.sqla import ModelView
  32.  
  33. # -------------- new -----------------
  34. from adminView import MyAdminIndexView, Accounts
  35.  
  36. admin = Admin(app, name='microblog', index_view=MyAdminIndexView(), base_template='backend.html')
  37.  
  38. import flask_login
  39. class BaseModelView(ModelView):
  40. def is_accessible(self):
  41. return flask_login.current_user.is_authenticated
  42.  
  43. admin.add_view(BaseModelView(User, db.session))
  44. admin.add_view(BaseModelView(Accounts, db.session))
  45. # -------------- new -----------------
  1. # manage.py
  2. from flask_script import Manager
  3. from hello import app
  4.  
  5. manager = Manager(app)
  6.  
  7. @manager.command
  8. def hello():
  9. """Print hello"""
  10. print("hello")
  11. from hello import db
  12.  
  13. @manager.command
  14. def initDB():
  15. """Initializes the database."""
  16. db.create_all(bind=None)
  17. if __name__ == "__main__":
  18. manager.run()
新增 adminView.py
  1. # adminView.py
  2. from flask import url_for, redirect, request
  3. from wtforms import form, fields, validators
  4. from flask_admin import Admin, AdminIndexView, helpers, expose
  5. from flask_login import LoginManager, current_user, login_user, logout_user
  6. from werkzeug.security import generate_password_hash, check_password_hash
  7.  
  8. from hello import db, app
  9.  
  10. # os.urandom(24)
  11. app.config['SECRET_KEY'] = b'\xe1\xa9\x7f9\xa6\x9cwe\xd01\x00\x18\xc2.\xad\x81\xf97Y\xd4wK9P'
  12.  
  13. # Create user model.
  14. class Accounts(db.Model):
  15. # 若不寫則看 class name
  16. __tablename__ = 'accounts'
  17. # 設定 primary_key
  18. id = db.Column(db.Integer, primary_key=True)
  19. username = db.Column(db.String(80), unique=True)
  20. email = db.Column(db.String(120))
  21. password = db.Column(db.String(64))
  22.  
  23. # Flask-Login integration
  24. def is_authenticated(self):
  25. return True
  26.  
  27. def is_active(self):
  28. return True
  29.  
  30. def is_anonymous(self):
  31. return False
  32. # for @login_manager.user_loader 使用
  33. def get_id(self):
  34. return self.id
  35.  
  36. def __repr__(self):
  37. return '<Accounts {}>'.format(self.username)
  38.  
  39. # 登入表格
  40. class LoginForm(form.Form):
  41. username = fields.TextField(validators=[validators.required()])
  42. password = fields.PasswordField(validators=[validators.required()])
  43.  
  44. def validate_username(self, field):
  45. user = self.get_user()
  46.  
  47. if user is None:
  48. raise validators.ValidationError('Invalid user')
  49.  
  50. # we're comparing the plaintext pw with the the hash from the db
  51. if not check_password_hash(user.password, self.password.data):
  52. # to compare plain text passwords use
  53. # if user.password != self.password.data:
  54. raise validators.ValidationError('Invalid password')
  55.  
  56. def get_user(self):
  57. return db.session.query(Accounts).filter_by(username=self.username.data).first()
  58.  
  59. # 註冊表格
  60. class RegistrationForm(form.Form):
  61. username = fields.TextField(validators=[validators.required()])
  62. email = fields.TextField()
  63. password = fields.PasswordField('New Password', [validators.DataRequired(),
  64. validators.EqualTo('confirm', message='Passwords must match')
  65. ])
  66. confirm = fields.PasswordField('Repeat Password')
  67. def validate_username(self, field):
  68. if db.session.query(Accounts).filter_by(username=self.username.data).count() > 0:
  69. raise validators.ValidationError('Duplicate username')
  70.  
  71. # 初始登入
  72. def init_login():
  73. login_manager = LoginManager()
  74. login_manager.init_app(app)
  75.  
  76. # Create user loader function
  77. @login_manager.user_loader
  78. def load_user(user_id):
  79. return db.session.query(Accounts).get(user_id)
  80.  
  81. # 建立 admin 的登入介面
  82. class MyAdminIndexView(AdminIndexView):
  83. @expose('/')
  84. def index(self):
  85. if not current_user.is_authenticated:
  86. return redirect(url_for('.login_view'))
  87. return super(MyAdminIndexView, self).index()
  88.  
  89. @expose('/login/', methods=('GET', 'POST'))
  90. def login_view(self):
  91. # handle user login
  92. form = LoginForm(request.form)
  93. if helpers.validate_form_on_submit(form):
  94. user = form.get_user()
  95. login_user(user)
  96.  
  97. if current_user.is_authenticated:
  98. return redirect(url_for('.index'))
  99. link = '<p>Don\'t have an account? <a href="' + url_for('.register_view') + '">Click here to register.</a></p>'
  100. self._template_args['form'] = form
  101. self._template_args['link'] = link
  102. return super(MyAdminIndexView, self).index()
  103.  
  104. @expose('/register/', methods=('GET', 'POST'))
  105. def register_view(self):
  106. form = RegistrationForm(request.form)
  107. if helpers.validate_form_on_submit(form):
  108. user = Accounts()
  109.  
  110. form.populate_obj(user)
  111. # we hash the users password to avoid saving it as plaintext in the db,
  112. # remove to use plain text:
  113. user.password = generate_password_hash(form.password.data)
  114.  
  115. db.session.add(user)
  116. db.session.commit()
  117.  
  118. login_user(user)
  119. return redirect(url_for('.index'))
  120. link = '<p>Already have an account? <a href="' + url_for('.login_view') + '">Click here to log in.</a></p>'
  121. self._template_args['form'] = form
  122. self._template_args['link'] = link
  123. return super(MyAdminIndexView, self).index()
  124.  
  125. @expose('/logout/')
  126. def logout_view(self):
  127. logout_user()
  128. return redirect(url_for('.index'))
  129.  
  130. # Initialize flask-login
  131. init_login()
新增 backend.html
  1. {% extends 'admin/base.html' %}
  2.  
  3. {% block access_control %}
  4. {% if current_user.is_authenticated %}
  5. <div class="btn-group pull-right">
  6. <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
  7. <i class="icon-user"></i> {{ current_user.login }} <span class="caret"></span>
  8. </a>
  9. <ul class="dropdown-menu">
  10. <li><a href="{{ url_for('admin.logout_view') }}">Log out</a></li>
  11. </ul>
  12. </div>
  13. {% endif %}
  14. {% endblock %}
新增 admin/index.html
  1. {% extends 'admin/master.html' %}
  2. {% block body %}
  3. {{ super() }}
  4. <div class="row-fluid">
  5.  
  6. <div>
  7. {% if current_user.is_authenticated %}
  8. <p class="lead">
  9. Authentication
  10. </p>
  11. <p>
  12. {{ current_user }} Example
  13. </p>
  14. {% else %}
  15. <form method="POST" action="">
  16. {{ form.hidden_tag() if form.hidden_tag }}
  17. {% for f in form if f.type != 'CSRFTokenField' %}
  18. <div>
  19. {{ f.label }}
  20. {{ f }}
  21. {% if f.errors %}
  22. <ul>
  23. {% for e in f.errors %}
  24. <li>{{ e }}</li>
  25. {% endfor %}
  26. </ul>
  27. {% endif %}
  28. </div>
  29. {% endfor %}
  30. <button class="btn" type="submit">Submit</button>
  31. </form>
  32. {{ link | safe }}
  33. {% endif %}
  34. </div>
  35.  
  36. <a class="btn btn-primary" href="/"><i class="icon-arrow-left icon-white"></i> Back</a>
  37. </div>
  38. {% endblock body %}
運行方法
# 介面網址為:http://127.0.0.1:5000/admin/
python manage.py runserver

Flask Blueprints
將 view 額外拆成另一個檔案 view.py,以便管理
  1. # hello.py
  2. from flask import Flask
  3. from view import simple_page
  4. app = Flask(__name__)
  5.  
  6. app.register_blueprint(simple_page)
  1. # manage.py
  2. from flask_script import Manager
  3. from hello import app
  4.  
  5. manager = Manager(app)
  6. if __name__ == "__main__":
  7. manager.run()
  1. # view.py
  2. from flask import Blueprint
  3.  
  4. simple_page = Blueprint('simple_page', __name__,
  5. template_folder='templates')
  6.  
  7. @simple_page.route('/')
  8. def hello_world():
  9. return 'Hello, World!'

參考

用 Flask 與 SQLite 架抽籤網站

留言