标签:
《Flask Web开发:基于Python的Web应用开发实战》
virtualenv venv venv\Scripts\activate.bat (venv) $ pip freeze >requirements.txt (venv) $ pip install -r requirements.txt pip list --outdated pip install --upgarade <Package1> <PackageN>
git tag 列出所有打tag的分支 git checkout <tag_name> 切换到tag git reset --hard 不保留修改.gitignore:指定哪些文件或目录不作同步,比如 ./venv/,*.pyc,数据库文件.sqlite3, .mysql
# -*- coding: utf-8 -*- from flask import Flask app = Flask(__name__)
@app.route('/') def index(): return '<h1>Hello World!</h1>'修饰器是Python语言的标准特性,可以使用不同的方式修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序。
@app.route('/user/<name>') def user(name): return '<h1>Hello, %s!</h1>' %name @app.route('/user/<int:id>') # 不能有空格! def ...
app.run(debug=True, port=7777)
app.url_map Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>, <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>, <Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])HEAD、Options、GET是请求方法,由路由进行处理。Flask为每个路由都指定了请求方法,这样不同的请求方法发送到相同的URL上时,会使用不同的视图函数进行处理。HEAD和OPTIONS方法由Flask自动处理
response = make_response('<h1>This document carries a cookie!</h1>', 200) response.set_cookie('answer', '42') return response
@app.route('/user/<name>') def user(name): return render_template('user.html', name=name)模板变量
<p>A value from a dictionary: {{ mydict['key'] }}.</p> <p>A value from a list: {{ mylist[3] }}.</p> <p>A value from a list, with a variable index: {{ mylist[myintvar] }}.</p> <p>A value from an object's method: {{ myobj.somemethod() }}.</p>
Hello, {{ name|capitalize }
<html> <head> {%block head %} <title>{%block title %}{%endblock %} - My Application</title> {%endblock %} </head> <body> {%block body %} {%endblock %} </body> </html>extends指令声明这个模板衍生自base.html。在extends指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super()获取原来的内容(向已经有内容的块中添加新内容)。
{%extends "base.html" %} {%block title %}Index{%endblock %} {%block head %} {{ super() }} <style> </style> {%endblock %} {%block body %} <h1>Hello, World!</h1> {%endblock %}使用Flask-Bootstrap
{% block head %} {{super()}} <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon"> <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon"> <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap-theme.min.css"> {% endblock %} 。。。 {% block scripts %} {{super()}} <script src="//cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <script src="//cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> {{ moment.include_moment() }} {{ moment.lang("zh-CN") }} {% endblock %}
自定义错误页面
@app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404url_for() 链接辅助函数
{%block scripts %} {{ super() }} {{ moment.include_moment() }} <!--使用中文,默认是英语的--> {{ moment.lang("zh-CN") }} {%endblock %}
from flask_wtf import Form from wtforms import StringField, SubmitField from wtforms.validators import DataRequired class NameForm(Form): name = StringField('What is your name?', validators=[DataRequired()]) submit = SubmitField('Submit')
password = PasswordField('Password', validators=[DataRequired()], render_kw={"placeholder": u"密码"})
@app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'))
MySQLdb 中文乱码的处理:
conn = MySQLdb.connect(host=‘localhost‘, user=‘root‘, passwd=‘XXX‘, db=‘app_englishgo‘, charset = ‘utf8‘)
显示:title.encode(‘gbk‘)
接收输入:unicode(request.form[‘title‘])
Relationship 关系型数据库
class Role(db.Model): # ... users = db.relationship('User', backref='role') # 面向对象视角 class User(db.Model): # ... role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) # 定义外键
engine = create_engine('sqlite:///C:\\Temp\\testsqlalchemy.db', encoding='utf8', convert_unicode=True, echo=True) # echo:显示出内部过程及SQL语句。debug或学习时打开 # encoding:防止乱码
'mysql://uid:pwd@localhost/mydb?charset=utf8'
集成Python shell
每次启动 shell 会话都要导入数据库实例和模型。为避免重复导入,我们可以做些配置,让 Flask-Script 的 shell 命令自动导入特定的对象。为 shell 命令注册一个 make_context 回调函数
新数据库迁移 flask-migrate
由于模型中经常会新加一行或几行column (比如用来保存账户的确认状态),此时要修改 models.py,并执行一次新数据库迁移
MySQL Workbench 自动产生EER,可以清楚地看到各个表格之间关系:一对多 Foreign_Key、Index等
1) config.py:
class DevelopmentConfig(Config): DEBUG = True # SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite') SQLALCHEMY_DATABASE_URI = 'mysql://USER:PASSWORD@localhost:3306/flaskr'2) python manage.py deploy
3) MySQL Workbench: Database -> Reverse Engineer -> 选择 connection -> database -> 一路 Next
app.config['MAIL_SERVER'] = 'smtp.163.com' app.config['MAIL_PORT'] = 25 app.config['MAIL_USE_TLS'] = True app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]' app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <flasky@example.com>' app.config['FLASKY_ADMIN'] = os.environ.get('FLASKY_ADMIN') mail = Mail(app) def sendmail(mail): msg = Message('test subject', sender='ezhqing@163.com', recipients = ['XXX@qq.com']) msg.body = 'text body' msg.html = '<b>HTML</b> body' with app.app_context(): mail.send(msg)千万不要把账户密令直接写入脚本,特别是当你计划开源自己的作品时。让脚本从本机环境中导入敏感信息
(venv) $ set MAIL_USERNAME=<your mail username> (venv) $ set MAIL_PASSWORD=<mail password>
|-flasky |-app/ Flask 程序一般都保存在名为 app 的程序包中 |-templates/ templates 和 static 文件夹是程序包的一部分 |-static/ |-main/ 程序包中创建了一个子包,用于保存蓝本。/main/__init__.py脚本的末尾导入views.py & errors.py,避免循环导入依赖 |-__init__.py 程序工厂函数 create_app(),注册蓝本 |-errors.py 错误处理路由. 注册程序全局的错误处理程序,必须使用 app_errorhandler |-forms.py 表单对象 |-views.py 路由。蓝本中的全部端点会加上一个命名空间,如 url_for('main.index') |-__init__.py |-email.py 电子邮件支持函数 |-models.py 数据库模型 |-migrations/ 数据库迁移脚本 |-tests/ 单元测试 |-__init__.py 文件可以为空,因为 unittest 包会扫描所有模块并查找测试 |-test*.py |-venv/ 虚拟环境 |-requirements.txt 列出了所有依赖包,便于在其他电脑中重新生成相同的虚拟环境 |-config.py 存储配置。开发、测试和生产环境要使用不同的数据库 |-manage.py 用于启动程序以及其他的程序任务
<ul class="nav navbar-nav navbar-right"> {% if current_user.is_authenticated %} <li><a href="{{ url_for('auth.logout') }}" title = "邮件 {{ current_user.email[:9]+'...' }}">Log Out {{ current_user.username }}</a></li> {% else %} <li><a href="{{ url_for('auth.login') }}">Log In</a></li> {% endif %} </ul>
user = User.query.filter_by(email=form.email.data).first() if user is not None and user.verify_password(form.password.data): login_user(user, form.remember_me.data) return redirect(request.args.get('next') or url_for('main.index'))
>>> from itsdangerous import TimedJSONWebSignatureSerializer as Serializer >>> s = Serializer(app.config['SECRET_KEY'], expires_in = 3600) >>> token = s.dumps({ 'confirm': 23 }) >>> token 'eyJhbGciOiJIUzI1NiIsImV4cCI6MTM4MTcxODU1OCwiaWF0IjoxMzgxNzE0OTU4fQ.ey ...' >>> data = s.loads(token) >>> data {u'confirm': 23}
<li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> <img height="24px" src="{{ url_for('static', filename='avatar/')}}{{ current_user.avatar_hash }}">
def gravatar(self, size=100, default='identicon', rating='g'): import random return '%.3d.jpg' % random.randint(1, XXX)
<div class="page-header"> <img class="img-rounded profile-thumbnail" src="{{ url_for('static', filename='avatar/')}}{{ current_user.avatar_hash }}"">
<li class="post"> <div class="post-thumbnail"> <a href="{{ url_for('.user', username=post.author.username) }}"> <img height="40px" class="img-rounded profile-thumbnail" src="{{ url_for('static', filename='avatar/')}}{{ post.author.avatar_hash }}">
<div class="comment-thumbnail"> <a href="{{ url_for('.user', username=comment.author.username) }}"> <img height="40px' class="img-rounded profile-thumbnail" src="{{ url_for('static', filename='avatar/')}}{{ post.author.avatar_hash }}">
python manage.py shell >>> User.generate_fake() >>> Post.generate_fake(200)
@manager.command def deploy(): """Run deployment tasks.""" from flask.ext.migrate import upgrade from app.models import Role, User # migrate database to latest revision upgrade() # create user roles Role.insert_roles() # create self-follows for all users User.add_self_follows() # 测试:User.generate_fake(100) # Post.generate_fake(500)
Write a Tumblelog Application with Flask and MongoEngine
这是MongoDB官方文档中的一个教程,也是学习Flask开发的一个很好案例,尤其适合Flask+MongoDB开发的应用场景
The Hitchhiker’s Guide to Python!
这个资料虽然不直接与Flask有关,但对初学者,绝对有学习的价值
GitHub - humiaozuzu/awesome-flask: A curated list of awesome Flask resources and plugins
https://spacewander.github.io/explore-flask-zh/7-blueprints.html
什么是蓝图?
一个蓝图定义了可用于单个应用的视图,模板,静态文件等等的集合。举个例子,想象一下我们有一个用于管理面板的蓝图。这个蓝图将定义像/admin/login和/admin/dashboard这样的路由的视图。它可能还包括所需的模板和静态文件。你可以把这个蓝图当做你的应用的管理面板,管它是宇航员的交友网站,还是火箭推销员的CRM系统。
蓝图的杀手锏是将你的应用组织成不同的组件。假如我们有一个微博客,我们可能需要有一个蓝图用于网站页面,比如index.html和about.html。然后我们还需要一个用于在登录面板中展示最新消息的蓝图,以及另外一个用于管理员面板的蓝图。站点中每一个独立的区域也可以在代码上隔绝开来。最终你将能够把你的应用依据许多能完成单一任务的小应用组织起来。
Flask.register_blueprint()
注册它。pip install flask-sqlalchemy
pip install flask-login
...
from flask.ext.bootstrap import Bootstrap
bootstrap = Bootstrap(app)
然后 /template/目录下创建自己的 html,{% extends "bootstrap/base.html" %}
模板:\Lib\site-packages\flask_bootstrap\templates\bootstrap\
Bootstrap 导航栏 自定义配色:
{% block styles %}
from flask_debugtoolbar import DebugToolbarExtension toolbar = DebugToolbarExtension() toolbar.init_app(app)
Flask之旅《Flask Web开发:基于Python的Web应用开发实战》学习笔记
标签:
原文地址:http://blog.csdn.net/kevin_qq/article/details/51594639