Flask 开发中的踩坑

flask中常用的包有:

  1. Flask
  2. Flask-Cache
  3. Flask-DebugToolbar
  4. Flask-Exceptional
  5. Flask-Login
  6. Flask-Mail
  7. Flask-RESTful
  8. Flask-Script
  9. Flask-SqlAlchemy
  10. Flask-Uploads
  11. Flask-WTF
  12. bcrypt
  13. gunicorn
  14. pymysql
  15. WTForms

1. Flask 目录结构的选择

按功能分层次

test-demo
├── config.py
├── instance
│   └── config.py
├── requirements.txt
├── run.py
└── test_demo
    ├── forms
    │   └── __init__.py
    ├── __init__.py
    ├── models
    │   ├── __init__.py
    │   └── User.py
    ├── static
    │   └── style.css
    ├── templates
    │   ├── admin
    │   │   └── base.html
    │   ├── api
    │   │   └── base.html
    │   └── base.html
    ├── utils
    │   └── __init__.py
    └── views
        ├── admin
        │   ├── __init__.py
        ├── api
        │   ├── __init__.py
        └── __init__.py

按模块分层次

.
├── config.py
├── instance
│   └── config.py
├── requirements.txt
├── run.py
└── test_demo
    ├── admin
    │   ├── forms
    │   │   └── __init__.py
    │   ├── models
    │   │   ├── __init__.py
    │   │   └── User.py
    │   ├── templates
    │   │   └── base.html
    │   ├── utils
    │   │   └── __init__.py
    │   └── views
    │       └── __init__.py
    ├── api
    │   ├── forms
    │   │   └── __init__.py
    │   ├── models
    │   │   ├── __init__.py
    │   │   └── User.py
    │   ├── static
    │   │   └── style.css
    │   ├── templates
    │   │   └── base.html
    │   ├── utils
    │   │   └── __init__.py
    │   └── views
    │       └── __init__.py
    └── __init__.py

各自优点:

  1. 按功能分层次的优点是各种功能联系紧密, 公用的代码易于管理。 适合中小型的项目。 比如blog, cms, 简易的网上商城。
  2. 按模块分层次的优点是将各个功能分离出来, 适合模块化的迁移和公用。 适合稍大的项目, 模块间联系不是很紧密的情况。

各自的缺点:

  1. 功能分层的话, 代码后期的迁移难度增加, 代码间的公用性太强, 容易牵一发而动全身。 而且当代码量增加之后, 维护性较差。
  2. 模块分层的话, 代码的冗余太多, 许多可以公用的地方无法很好处理, 构造繁琐, 工期较长。

flask结构常见文件的作用

  1. config.py 主要存放配置信息。 比如DEBUG, mysql, sercertkey等。 可以通过flask的 app.config.from_object('config') 自动导入。
  2. instance/config.py 主要是私人的信息, 可以通过 flask 提供的 app.config.from_pyfile('config.py') 覆盖前者的配置。
  3. requirements 存放所需要引入的包。
  4. run.py 运行文件, 加入一些运行配置, 比如使用gunicorn配置, 也可以通过添加manager.py文件管理。
  5. views 文件存放路由信息, 俗称蓝图。 类似于MVC架构中的controllers。
  6. models 数据存放与处理的信息。 类似MVC中的Models。
  7. forms 表单存放的位置。
  8. static 静态文件的存放。 images/js/css
  9. templates jinja模板文件。
  10. utils 一些常用的方法集合。

2. 使用nginx反向代理时候的域名前缀的坑

如果想要设置网站的访问为 api.example.com, admin.example.com, example.com。 最简单的方式就是用nginx来做反向代理。
example.com主要就是传输静态的文件的地址。 主要是主页面和css, js。 可以直接使用nginx获取静态资源, 效率十分高。
api.exmaple.com 和 admin.example.com 则需要代理指向python去执行。 坑出现了。

server {
        listen 80;
        server_name api.fos.dev;
        server_name admin.fos.dev;

        location / {
            proxy_pass http://127.0.0.1:5000;
            proxy_read_timeout 86400s;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
}

本来是这样配置的nginx, 这时候, flask获取到的server_name 其实是 127.0.0.1:5000这个东西, 但是这个东西无法添加subdomain. 也就是无法这样显示:
api.127.0.0.1:9000, admin.127.0.0.1:9000
因此这儿需要对nginx做一些配置上的调整。

server {
        listen 80;
        server_name api.fos.dev;
        server_name admin.fos.dev;

        location / {
            proxy_pass http://127.0.0.1:5000;
            proxy_read_timeout 86400s;
            proxy_http_version 1.1;
            proxy_set_header Host            $host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
}

添加了

proxy_set_header Host            $host;
proxy_set_header X-Forwarded-For $remote_addr;

将nginx接受到的 server_name 传递过去。
此时也必须设置flask的SERVER_NAME参数, 即config.py文件里面的SERVER_NAME = 'fos.dev'.
这样就可以大功告成了。

3. mysql包的选择

Flask-SQLAlchemy包默认使用的是MYSQL-python包.
显然这个包已经两年多没有更新了, 所以已经是一个死包了, 而且只支持到2.7版本。
现在还有一个包pymysql, 这才是未来啊。
使用pymysql包只需将config.py里面的:

SQLALCHEMY_DATABASE_URI = 'mysql://username:password@server/fos'

改为

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://username:password@server/fos'

这个包支持 2 ~ 3.5.

4. relations 关联表的设置问题。

关联表ontToMany之间使用的是

#products.py表 一对多
product_images = db.relationship('ProductImage', back_populates='product', lazy='dynamic')

#product_image表 多对一
product_id = db.Column(db.Integer, db.ForeignKey('products.id'))
product = db.relationship("Product", back_populates="product_images")

使用的是 对象的名字来代表该表。 如ProductImage, Product, 这样使用的时候,必须确保改对象也在当前文件中, 如果是不同的文件,就需要将另一个文件导入。
因此, 在最外层的init.py中统一导入了所有的对象。

5. flask-script包主要用于自定义一些命令行command.

简单的命令行很好写, 值得说的是带参数的命令行.
第一种是可选单参数(-f, -v, -h)之类的

@manager.command
def db_create(force=False):
    pass

这段代码中的force参数就是如此, 可以通过 db_create 之后加上 -f/--force赋值True, 否则其他的均为False, 包括直接 python manage.py db_create force

@manager.option('-u', '--name', dest='name', default='admin')
@manager.option('-p', '--password', dest='password', default='123456')
def create_user(name, password):
    pass

这段代码则是配置多参数的例子, -u/--name 后面输入的均作为name参数, 比如

python manage.py create_user -u admin

或者

python manage.py create_user --name admin

6. wtforms

如果是一个select 表单, 内容是 sqlalchemy 的对象

# productForm中的category设置方法
category_id = SelectField('category',
    choices=[(str(c.id), c.name) for c in Category.query.order_by('name')],
    validators=[
        DataRequired()
    ])

尤其注意的是, choices的value值必须设置为str类型, 因为form表单传送过来的是string, python是强类型的语言,所以用string对应。

fieldList的使用

# product_image中的设置
class MultiProductImageForm(BaseForm):
    images = FieldList(FileField('Image File',
        validators=[
            DataRequired(),
            ImageFileRequired()
        ]), min_entries=1)

min_entries这个参数必须是kw, 而且只能在初始时期绑定, 后期调用init方法绑定的话, 参数传递会有问题, 有机会重写一下, 或者重写它的 new方法。
总体来说这个包不够自动化,需要填的坑很多,慎用。

有关的实践代码在点此 github

你可能感兴趣的:(Flask 开发中的踩坑)