Flask 项目实战教程。。。

flask 不仅简介小巧,同时运用的时候十分灵活。下面简单介绍一下如何编写一个 flask项目。涉及调用开发服务器,数据库连接以及 ORM 映射,还有数据库的迁移,模板使用。后期再完善会话,管理后台,缓存等。


一 安装环境
我们使用 flask web框架,并用 sqlalchemy来做数据库映射,并使用 migrate做数据迁移。

[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ pip install flask  
  2. $ pip install SQLAlchemy==0.7.9  
  3. $ pip install flask-sqlalchemy  
  4. $ pip install flask-migrate  

二 建立项目

flask 没有 django 那样原生的 manage管理工具(flask-admin可以实现,日后再说)。因此我们需要手动建立目录。新建一个 myproject目录,在里面建 app tmp两个文件夹,然后在 app文件夹里面建立 static, templates 两个文件夹,用来存储静态文件和模板。最后目录结构如下:

.
├── app
│   ├── static
│   ├── templates
└── tmp


三 初始化文件


建立一些文件,在 app文件里建立 __init__.py models.py views.py 然后在与app 同目录下建立 config.py 和 run.py 此时的目录结构如下:


(env)ghost@ghost-H61M-S2V-B3:~/project/python/flask/project$ tree
.
├── app
│   ├── static
│   ├── templates
│   ├── __init__.py
│   ├── models.py
│   ├── views.py
├── config.py
├── run.py
└── tmp


四 开始项目


1 hello wrod

打开 (/app/__init.py) 文件,写入

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3. from flask import Flask        # 引入 flask   
  4.   
  5. app = Flask(__name__)          # 实例化一个flask 对象  
  6.   
  7. import views                   # 导入 views 模块  
  8. # from app import views  


注意,我们的 app 文件夹其实是一个python包,from app import views 这句话也就是从 包app里面导入 views模块,所以写成注释的那句话也没错,其他代码实践喜欢写成后面那种

现在我们来开始写我们的视图,打开 (/app/views.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3. from app import app  
  4. from models import User, Post, ROLE_USER, ROLE_ADMIN  
  5.  
  6. @app.route('/')  
  7. def index():  
  8.     return 'hello world, hello flask'  

下一步我们将要启动我们的开发服务器,打开 (/run.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3. from app import app            
  4.   
  5. if __name__ == '__main__':  
  6.     app.debug = True           # 设置调试模式,生产模式的时候要关掉debug  
  7.     app.run()                  # 启动服务器  

这段代码需要注意第一句 from app import app。也许会有疑问,我们的 app 包里,貌似没有 app.py 这样的模块。其实这是 flask 方式和python的导入方式。from app 指导入 app 包里的 __iniy__.py 所以这句话的含义是导入 __.init__.py 里面的 app实例。

打开shell 运行 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ python run.py  
  2.   
  3.   
  4. (env)ghost@ghost-H61M-S2V-B3:~/project/python/flask/project$ python run.py   
  5.  * Running on http://127.0.0.1:5000/  
  6.  * Restarting with reloader  

用浏览器打开 http://127.0.0.1:5000/  将会看到一个输入 hello world 的页面

2 连接数据库

下面开始连接数据库引擎 先要做一个简单的配置 打开 (/config.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. import os  
  5. basedir = os.path.abspath(os.path.dirname(__file__))  
  6.   
  7.   
  8. SQLALCHEMY_DATABASE_URI = 'sqlite:///%s' % os.path.join(basedir, 'app.db')  
  9. SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')  
  10.   
  11.   
  12. CSRF_ENABLED = True  
  13. SECRET_KEY = 'you-will-never-guess'  

然后打开 (/app/__init__.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. import os  
  5. from flask import Flask  
  6. from flask.ext.sqlalchemy import SQLAlchemy  
  7. from config import basedir  
  8.   
  9.   
  10. app = Flask(__name__)  
  11.   
  12.   
  13. app.config.from_object('config')   # 载入配置文件  
  14.   
  15.   
  16. db = SQLAlchemy(app)               # 初始化 db 对象  
  17.   
  18.   
  19. # from app import views, models    # 引用视图和模型  
  20. import views, models  


打开 (/app/models.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. from app import db  
  5.   
  6.   
  7. ROLE_USER = 0  
  8. ROLE_ADMIN = 1  
  9.   
  10.   
  11. class User(db.Model):  
  12.   
  13.   
  14.     id = db.Column(db.Integer, primary_key=True)  
  15.     nickname=db.Column(db.String(60), index=True, unique=True)  
  16.     email = db.Column(db.String(120), index=True, unique=True)  
  17.     role = db.Column(db.SmallInteger, default=ROLE_USER)  
  18.   
  19.   
  20.     def __repr__(self):  
  21.         return '<User %r>' % self.nickname  


我们的模型建立了一个 user类,正好是 数据库里面的 user 表,表有四个字段

现在我们的数据库配置已经好了,可是还没有建立数据库。新建一个文件 (/db_create.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. from migrate.versioning import api  
  5. from config import SQLALCHEMY_DATABASE_URI  
  6. from config import SQLALCHEMY_MIGRATE_REPO  
  7. from app import db  
  8. import os.path  
  9.   
  10.   
  11. db.create_all()  
  12.   
  13.   
  14. if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):  
  15.     api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')  
  16.     api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)  
  17. else:  
  18.     api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, api.version(SQLALCHEMY_MIGRATE_REPO))  
  19.       

这个脚本是完全通用的,所有的应用路径名都是从配置文件读取的。当你用在自己的项目时,你可以把脚本拷贝到你的项目目录下就能正常使用了。

打开shell 运行 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ python db_create_db  

运行这条命令之后,你就创建了一个新的app.db文件。这是个支持迁移的空sqlite数据库,同时也会生成一个带有几个文件的db_repository目录,这是SQLAlchemy-migrate存储数据库文件的地方,注意如果数据库已存在它就不会再重新生成了。这将帮助我们在丢失了现有的数据库后,再次自动创建出来。


运行 
[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. slqite3 app.db  
  2. >>> .tables  
  3. >>> user  

或者使用 sqlite 图形化客户端,没有需要安装 (windows 下直接下载安装包即可)


[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ sudo apt-get install sqlitebrowser   


3 数据库迁移

每当我们更改了 models 。等价于更改了数据库的表结构,这个时候,需要数据库同步。新建  (/db_mirgate.py)


[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. import imp  
  5. from migrate.versioning import api  
  6. from app import db  
  7. from config import SQLALCHEMY_DATABASE_URI  
  8. from config import SQLALCHEMY_MIGRATE_REPO  
  9.   
  10.   
  11. migration = SQLALCHEMY_MIGRATE_REPO + '/versions/%03d_migration.py' % (api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO) + 1)  
  12. tmp_module = imp.new_module('old_model')  
  13. old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)  
  14.   
  15.   
  16. exec old_model in tmp_module.__dict__  
  17. script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, tmp_module.meta, db.metadata)  
  18.   
  19.   
  20. open(migration, "wt").write(script)  
  21. api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)  
  22.   
  23.   
  24. print 'New migration saved as ' + migration  
  25. print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))  

这个脚本看起来很复杂,SQLAlchemy-migrate通过对比数据库的结构(从app.db文件读取)和models结构(从app/models.py文件读取)的方式来创建迁移任务,两者之间的差异将作为一个迁移脚本记录在迁移库中,迁移脚本知道如何应用或者撤销一次迁移,所以它可以方便的升级或者降级一个数据库的格式。

开始数据库迁移

$ python db_mirgate.py

New migration saved as db_repository/versions/001_migration.py  Current database version: 1

相应的,我们继续创建数据库 升级和回退的脚本

(/db_upgrade)


[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. from migrate.versioning import api  
  5. from config import SQLALCHEMY_DATABASE_URI  
  6. from config import SQLALCHEMY_MIGRATE_REPO  
  7.   
  8.   
  9. api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)  
  10.   
  11.   
  12. print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))  

(/db_downgrade.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. from migrate.versioning import api  
  5. from config import SQLALCHEMY_DATABASE_URI  
  6. from config import SQLALCHEMY_MIGRATE_REPO  
  7.   
  8.   
  9. v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)  
  10. api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)  
  11.   
  12.   
  13. print 'Current database version: ' + str(api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO))  


4 操作数据库


接下来,我们定义一个新的models class 并做第二次迁移归并

打开(/app/models.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. from app import db  
  5.   
  6.   
  7. ROLE_USER = 0  
  8. ROLE_ADMIN = 1  
  9.   
  10.   
  11. class User(db.Model):  
  12.   
  13.   
  14.     id = db.Column(db.Integer, primary_key=True)  
  15.     nickname=db.Column(db.String(60), index=True, unique=True)  
  16.     email = db.Column(db.String(120), index=True, unique=True)  
  17.     role = db.Column(db.SmallInteger, default=ROLE_USER)  
  18.     posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')  
  19.   
  20.   
  21.   
  22.   
  23.     def __repr__(self):  
  24.         return '<User %r>' % self.nickname  
  25.   
  26.   
  27. class Post(db.Model):  
  28.   
  29.   
  30.     id = db.Column(db.Integer, primary_key=True)  
  31.     body = db.Column(db.String(140))  
  32.     timestamp = db.Column(db.DateTime)  
  33.     user_id = db.Column(db.Integer, db.ForeignKey('user.id'))  
  34.   
  35.   
  36.     def __repr__(self):  
  37.         return '<Post %r>' % (self.body)  


这里我们进行了两个class 的关联。

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ python db_mirgrate.py  
  2.   
  3.   
  4. New migration saved as db_repository/versions/002_migration.py  Current database version: 2  


打开 (/app/views.py)

[python]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2.   
  3.   
  4. from flask import render_template, flash, redirect, session, url_for, request, g  
  5. from app import app, db  
  6. from models import User, Post, ROLE_USER, ROLE_ADMIN  
  7.  
  8.  
  9. @app.route('/')  
  10. def index():  
  11.     return render_template('index.html')  
  12.  
  13.  
  14. @app.route('/adduser/<nickname>/<email>')  
  15. def adduser(nickname, email):  
  16.     u = User(nickname=nickname, email=email)  
  17.     try:  
  18.         db.session.add(u)  
  19.         db.session.commit()  
  20.         return 'add successful'  
  21.     except Exception, e:  
  22.         return 'something go wrong'  
  23.      
  24. @app.route('/getuser/<nickname>')  
  25. def getuser(nickname):  
  26.     user = User.query.filter_by(nickname=nickname).first()  
  27.   
  28.   
  29.     return render_template('user.html', user=user)  
  30.  
  31.  
  32. @app.errorhandler(404)  
  33. def internal_error(error):  
  34.     return render_template('404.html'), 404  
  35.  
  36.  
  37. @app.errorhandler(500)  
  38. def internal_error(error):  
  39.     db.session.rollback()  
  40.     return render_template('500.html'), 500  


这次我们使用了模板, 新建(/app/templates/user.html)

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <html>  
  2. <head>  
  3.     <title>user</title>  
  4. </head>  
  5. <body>  
  6.     <h1>user</h1>  
  7.     <ul>  
  8.         <li>user: {{ user.nickname }}</li>  
  9.         <li>email: {{ user.email }}</li>  
  10.     </ul>  
  11. </body>  
  12. </html>  

最后运行 

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ python run.py  


用浏览器访问 http://127.0.0.1:5000/adduser/username/useremail


最后还可以用 sqlite 客户端打开查看我们的数据库变换。关于更多的数据库操作方法,请阅读 sqlalchemy文档。


最后我们的代码目录结构如下:


(env)ghost@ghost-H61M-S2V-B3:~/project/python/flask/project$ tree
.
├── app
│   ├── __init__.py
│   ├── models.py
│   ├── static
│   ├── templates
│   │   ├── 404.html
│   │   ├── 500.html
│   │   ├── index.html
│   │   └── user.html
│   ├── views.py
├── app.db
├── config.py
├── db_create.py
├── db_downgrade.py
├── db_migrate.py
├── db_repository
│   ├── __init__.py
│   ├── manage.py
│   ├── migrate.cfg
│   ├── README
│   └── versions
│       ├── 001_migration.py
│       ├── 002_migration.py
│       ├── __init__.py
├── db_upgrade.py
├── requirements.txt
├── run.py
├── tmp



代码下载:  https://github.com/rsj217/flask-extend/tree/master/project
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值