Day 10 实作基本档案

前言

今天我们会实作 config.pyrequirements.txt,并稍微介绍一下这些套件大概要干嘛。我们把两个分开来慢慢看。

在开始之前,我们要先讲一下环境变数。很多资讯我们不会直接放在 config.py 里面,而是要从环境变数去抓,这样我们才不会把敏感的资讯 (如密码、token 等等) 直接暴露在原始码中。设置环境变数因作业系统而异,可以参考 Windows cmdWindows PowerShelllinux,在此处不赘述。而我们要在 python 中抓到环境变数则需要使用 os.getenv 这个函式,在後面的范例我们会直接 from os import getenv,所以全部都会使用 getenv 来呈现,有关其用法可以参考 Python | os.getenv() method

requirements.txt

直接来看看我们有那些需要的套件,我们会一项一项分开介绍。


Flask
Flask-SQLAlchemy
Flask-WTF
Flask-Login
Flask-Migrate
Flask-Mail
Flask-Markdown
Flask-Pagedown

第一个是 flask,这就不必再提了。

  • Flask-SQLAlchemy 是一个资料库的 ORM 框架,它的好处是不用担心 SQL injection,然後也会比较好写,因为就是用 python 的风格在写的。此外,他支援多种资料库,所以我们只需要写一次程序码就可以给多种资料库使用。但相对的,因为要透过一层 python 的转换,效能上必定有差。
  • 之前在说 flask 的 request 的时候有提到一个东西叫做 request.form,但我们没有深入去了解,就是因为我们使用了 Flask-WTF。他可以用物件的方式来建立我们需要的表单,而且也支援很多验证,像是正规表示式 (regex)、长度、是否为空等等,如果需要用 reCAPTCHA 也可以用他。此外,他也可以防止 CSRF (利用 csrf_token),是一个安全而且方便的表单工具。
  • Flask-Login 套件如其名,就是负责处理使用者验证的套件,後面会非常大幅的提到他。
  • Flask-Migrate 是用来管理资料库版本的,当我们资料库的结构有变动的时候,就可以让他帮忙自动更新,减少人为的错误。他需要配合 Flask-SQLAlchemy
  • Flask-Mail 一样套件如其名,就是用来处理寄信的套件,在下面的设定档会有更多细节。这个套件我觉得可选,不加入并不会导致整个 application 无法运作,我把他加入专案的原因只是想展现一次这个套件的功能。
  • Flask-Markdown 会帮我们加入一个 markdown 的 jinja filter,这样就可以直接在前端弄出 markdown。
  • Flask-Pagedown 是一个可以让我们边编辑边看 markdown 输出的套件,这个之後会跟 Flask-WTF 一起玩。

config.py

再来要看的是 config.py,他会放在 app/ 里面,而我们也有一些是三个共通的设定,所以他们三个都会继承自 Config 这个物件,现在就来看看它长甚麽样子。请注意前面需要 from os import getenv

class Config:
    # Flask-Mail
    MAIL_SERVER = "smtp.gmail.com"
    MAIL_PORT = 465
    MAIL_USE_SSL = True
    MAIL_USERNAME = getenv("MAIL_USERNAME")
    MAIL_PASSWORD = getenv("MAIL_PASSWORD")
    # Flask-SQLAlchemy
    SQLALCHEMY_TRACK_MODIFICATIONS = False

它分成 Flask-MailFlask-SQLAlchemy 两个部分,我们两个分开讲。

  • 如刚刚所说,Flask-Mail 是用来处理寄信的套件,所以他当然需要知道怎麽寄信。我们会使用 gmail 来寄信,所以 MAIL_USERNAMEMAIL_PASSWORD 都是 gmail 的资讯。这样填完之後基本上来无法寄信,需要到 Google Account Security 里面把「低安全性应用程序存取权」打开 (可参考 Send Gmail with Python),这样才能够寄信。如果不想用 gmail 也可以用其他邮件服务器,但就需要去翻一下他的文件了。
  • 第二个是有关 Flask-SQLAlchemy 的设定,非常简单只有短短一行。这个设定其实无伤大雅,他是一个让你可以开关事件系统 (event system) 的设定,基本上来说我们不需要他,但如果不关掉的话,他会在每次打开的时候送你警告,非常烦而且碍眼,所以关掉。此外,如果开着的话他会占用额外的记忆体资源,为了减少主机负担,就把他关了吧。

接下来我们来看看三个环境分别的设定。在这里我们需要用到 os.urandom 这个函式来生成之前提过的 SECRET_KEY,同样地,我们使用 from os import urandom 来引入。

class Testing(Config):
    # Flask
    ENV = "TESTING"
    TESTING = True
    SECRET_KEY = "cyn54g544mxng"
    SERVER_NAME = "localhost"
    # Flask-SQLAlchemy
    SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
    # Flask-WTF
    WTF_CSRF_ENABLED = False


class Development(Config):
    # Flask
    ENV = "DEVELOPMENT"
    DEBUG = True
    SECRET_KEY = "cyn54g544mxng"
    # Flask-SQLAlchemy
    SQLALCHEMY_DATABASE_URI = "sqlite:///data.db"


class Production(Config):
    # Flask
    ENV = "PRODUCTION"
    SECRET_KEY = urandom(32)
    # Flask-SQLAlchemy
    SQLALCHEMY_DATABASE_URI = getenv("DATABASE_URI")

我们以一个一个设定的名称来解释,前面一样有注解来表示他是关於甚麽套件的设定。

  • ENV 就是代表环境 (environment)。有些其他的环境变数也可能会被影响,像是马上要讲到的 DEBUG
  • DEBUG 是指示 flask 要不要开起 debug 工具用的,这些工具之前有提过了。如果 ENV=development,那 DEBUG 会自动设为 True
  • SECRET_KEY 之前也提过,是用来处理一些登入、session 相关的事情用的。理论上我们会用 urandom 来生成 (如 production),但因为他如果改变的话会让旧的 session 都失效,开发的时候要一直重新登入很烦,所以就让它静态。
  • TESTING 会让 flask 开启一些测试用的功能,而且有些套件的功能可能会改变,像是 Flask-MailTESTING=True 的时候就不会真的寄信出去,而是会打在 console。
  • SERVER_NAME 在这里是专门给测试用的,因为他跟平常使用的时候会有不一样的状态,所以会导致 url_for 无法使用。
  • SQLALCHEMY_DATABASE_URI 是用来指定资料库位置的设定,像我们开发的时候用 sqlite,就把档案放在同一个目录;测试的时候资料量不大,就把它放在记忆体就好;真正上线的时候就看环境要给甚麽,如果换一个资料库的话就会把前面的 sqlite: 改掉。要特别注意一下他有三个 /,而放在记忆体的话前後有冒号。
  • 前面有提到 flask-wtf 可以处理 CSRF 的攻击,他用的就是 csrf_token,而 WTF_CSRF_ENABLED 就是用来设定要不要打开 csrf_token 的设定。因为在测试的时候,我们不会像正常在使用一样实际按下送出,而是直接传资料到後端,所以就会被 csrf_token 挡下来。因为如此,我们在测试的时候会把它关掉,让测试顺利一点,反正测试不会攻击我们。
  • 最後我们还需要加入一个小小的 dict,这样到时候制造 app 的时候才有对照表,我们把环境的名称对到他们分别要用到的设定档,这个东西会在明天使用到。
configs = {
    "development": Development,
    "testing": Testing,
    "production": Production,
}

References

ORM 介绍及 ORM 优点、缺点
What are database migrations?
Flask-SQLAlchemy Configuration
Flask-Mail-example
Flask实作_ext_09_Flask-Mail_邮件发送
How do I know if I can disable SQLALCHEMY_TRACK_MODIFICATIONS?
SQLALCHEMY: how to use @events.listens_for in flask_sqlalchemy-SQLalchemy
Configuring Flask-Mail
Flask Builtin Configuration Values
Things You Should Know About Flask SERVER_NAME


<<:  网络框架

>>:  Day 10-自动化是工作标准化与效率的体现,Github Action 做 Terraform 自动化

Python Flask API 初探

昨天架设完Python环境後, 今天要开始架设Python API的专案, 而我们今天使用的是Fla...

Day 5 基本型别 - part 2

今天要介绍其他的型别,是原本的 JavaScript 没有的,分别是 Tuple、Enum、Any、...

Day06 - 监控 Sidekiq 有无正常运作(或执行超过多久)

前言 去年介绍过 Day25 - Ruby on Rails 中的 Sidekiq 的介绍与应用 ,...

《Day27》Oracle Database 安装

Oracle Database是由甲骨文公司推出的大型关联式资料库系统,提供基於角色分工的安全保密观...

VoK 系统功能权责划分 ( I ) - day13

权责划分 续VoK整合登入 当使用者登入系统後,无论是因为使用者权责亦或是为了系统安全,通常会建立适...