Flask实战

留言板

创建项目目录messageboard,从GreyLi的代码中把Pipfile和Pipfile.lock文件拷贝过来,这两个文件中定义了虚拟环境中需要安装的包的信息和位置,进入messageboard目录使用pipenv创建虚拟环境,这会同时安装所有依赖(--dev选项用来包括开发依赖), 安装完成后激活虚拟环境。

安装虚拟环境

pipenv install –dev

激活:

flask shell

查看虚拟环境中安装的包:

Pipfile:用来下载依赖包的
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi" [dev-packages]
watchdog = "*"
faker = "*" [packages]
bootstrap-flask = "*"
flask-moment = "*"
flask-sqlalchemy = "*"
python-dotenv = "*"
flask-wtf = "*"
flask = "*"
Pipfile.lock: 用来下载依赖包的
{
"_meta": {
"hash": {
"sha256": "90ecde6aebc889b8de105fb6b1394a6900ce33cf1be970cba63c0f6d56b158df"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"bootstrap-flask": {
"hashes": [
"sha256:1f7462261b8104687807ce74b397270e7ade07c491ad7d53f215940d8433d756",
"sha256:ce5cf19c46b8d385923dc2f9ca76b92fc08c1a8d7dcb5d177325a85a94d71045"
],
"index": "pypi",
"version": "==1.0.9"
},
"click": {
"hashes": [
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
],
"version": "==6.7"
},
"flask": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
],
"index": "pypi",
"version": "==1.0.2"
},
"flask-moment": {
"hashes": [
"sha256:71a601fcd5be4742227251641cb706c109680b54c5fb25c5d2ed96e576ec3b4d",
"sha256:af7ccd599d85e751ff1f7661904daa51df9950e9bc9bd4ccf174bd38ccbc401f"
],
"index": "pypi",
"version": "==0.6.0"
},
"flask-sqlalchemy": {
"hashes": [
"sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b",
"sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53"
],
"index": "pypi",
"version": "==2.3.2"
},
"flask-wtf": {
"hashes": [
"sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36",
"sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac"
],
"index": "pypi",
"version": "==0.14.2"
},
"itsdangerous": {
"hashes": [
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
],
"version": "==0.24"
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"python-dotenv": {
"hashes": [
"sha256:4f3582904d08dac5ab4c9aa44cb17ce056c9a35e585cfda6183d80054d247307",
"sha256:cb8cd327109898c7725f76c5256a081e8a9efe72ebbf127f8d1221ceb7f38bf2"
],
"index": "pypi",
"version": "==0.10.0"
},
"sqlalchemy": {
"hashes": [
"sha256:72325e67fb85f6e9ad304c603d83626d1df684fdf0c7ab1f0352e71feeab69d8"
],
"version": "==1.2.10"
},
"werkzeug": {
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
],
"version": "==0.14.1"
},
"wtforms": {
"hashes": [
"sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61",
"sha256:e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1"
],
"version": "==2.2.1"
}
},
"develop": {
"argh": {
"hashes": [
"sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3",
"sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65"
],
"version": "==0.26.2"
},
"faker": {
"hashes": [
"sha256:0e9a1227a3a0f3297a485715e72ee6eb77081b17b629367042b586e38c03c867",
"sha256:b4840807a94a3bad0217d6ed3f9b65a1cc6e1db1c99e1184673056ae2c0a4c4d"
],
"index": "pypi",
"version": "==0.8.17"
},
"ipaddress": {
"hashes": [
"sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794",
"sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c"
],
"markers": "python_version == '2.7'",
"version": "==1.0.22"
},
"pathtools": {
"hashes": [
"sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"
],
"version": "==0.1.2"
},
"python-dateutil": {
"hashes": [
"sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0",
"sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8"
],
"version": "==2.7.3"
},
"pyyaml": {
"hashes": [
"sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b",
"sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf",
"sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a",
"sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3",
"sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1",
"sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1",
"sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613",
"sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04",
"sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f",
"sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537",
"sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531"
],
"version": "==3.13"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
},
"text-unidecode": {
"hashes": [
"sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d",
"sha256:801e38bd550b943563660a91de8d4b6fa5df60a542be9093f7abf819f86050cc"
],
"version": "==1.2"
},
"watchdog": {
"hashes": [
"sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162"
],
"index": "pypi",
"version": "==0.8.3"
}
}
}

使用包组织代码

把所有的代码都放在app.py里会导致可读性降低,不方便管理,我们需要更好的代码组织方式。

Flask对项目的组织方式没有要求,对于小型项目,你完全可以把代码都放在一个主模块里,随着项目越来越大,更好的处理方式是将单一的模块升级为包(package),把不同部分的代码分模块存放。

在python中,每一个有效的python文件(.py)都是模块。每一个包含__init__.py文件的文件夹都被视作包,包让你可以使用文件夹来组织模块。__init__.py文件通常被称作构造文件。文件可以为空,也可以用来放置包的初始化代码。当包或包内的模块被导入时,构造文件将被自动执行。

messageboard程序的核心组件都放到一个包中,这个包称为程序包,包的程序通常使用程序名称,即messageBoard,有时为了方便管理也会使用app作为包名称。除了程序代码,一个基本的Flask项目还包括其他必要的组件,下面列一下程序包主要组件及其功能说明:messageBoard/  --程序包

messageBoard/__init__.py  --构造文件,包含程序实例

messageBoard/templates/  --模板

messageBoard/static/  --静态文件,其中又包含js和css文件夹

messageBoard/views.py  --视图函数

messageBoard/forms.py  --表单

messageBoard/errors.py  --错误处理

messageBoard/models.py  -- 数据库模型

messageBoard/commands.py  -- 自定义flask命令

messageBoard/settings.py  -- 配置文件

在后面的开发中,各类代码都会按照类别存储在对应的模块中。这里的模块并不是固定的,如果需要组织其他代码,那么可以自己创建对应的模块。比如,创建一个callbacks.py脚本来存储各种注册在程序实例上的处理函数。相对的,如果不需要创建自定义命令,那么也可以不创建commands.py脚本。

配置文件

在flask中,配置不仅可以通过config对象直接写入,还可以从文件中读取。在messageBoard中,把配置移动到一个单独的文件中,将其命名为settings.py(也常被命名为config.py)。当在单独的文件中定义配置时,不再使用config对象添加配置,而是直接以键值对的方式先写出,和保存环境变量的.flaskenv文件非常相似。

messageBoard/settings.py:配置文件
#encoding=utf-8
import os from messageBoard import app dev_db = 'sqlite:///' + os.path.join(os.path.dirname(app.root_path), 'data.db') #sqlite绝对路径格式 SECRET_KEY = os.getenv('SECRET_KEY', 'secret string')
SQLALCHEMY_TRACK_MODIFICATIONS = False # 不追踪对象的修改
SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URI', dev__db)

除了从python脚本导入配置,Flask还提供了其他方式,比如使用from_json()方法从JSON文件中导入,或是使用from_object()方法从python对象导入。

上面的配置中,由于配置文件被放到了程序包内,为了定位到位于项目根目录的数据库文件,使用os.path.dirname(app.root_path)获取上层目录,app.root_path属性存储程序实例所在的路径。数据库URI和秘钥都会首先从环境变量获取。

在创建程序实例后,使用config对象的from_pyfile()方法即可加载配置,传入配置模块的文件名作为参数:

messageBoard/messageBoard/__init__.py:

messageBoard/messageBoard/__init__.py:

app = Flask(__name__)
app.config.from_pyfile('settings.py')
创建程序实例

使用包组织程序代码后,创建程序实例、初始化扩展等操作可以在程序包的构造文件(__init__.py)中实现,如下所示:

messageBoard/__init__.py: 创建程序实例、初始化扩展

#encoding=utf-8

from flask import Flask
from flask_sqlalchemy import SQLAlchemy app = Flask('messageBoard')
app.config.from_pyfile('settings.py')
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True db = SQLAlchemy(app) from messageBoard import views, errors, commands

在单个脚本中创建程序实例时,我们传入__name__变量作为Flask类构造方法的import_name参数值。因为Flask通过这个值来确认程序路径,当使用包组织代码时,为了确保其他扩展或测试框架获得正确的路径值,我们最好以硬编码的形式写出包名称作为程序名称,即messageBoard。

除了直接写出包名称,你也可以从__name__变量获取包名称,即app=Flask(__name__.split(‘.’)[0])。

当我们启动程序时,首先被执行的是包含程序实例的脚本,即构造文件。但注册在程序实例上的各种处理程序均存放在其他脚本中,比如视图函数存放在view.py中、错误处理函数则存放在errors.py中。为了能使用程序实例app注册的视图函数,错误处理函数,自定义命令函数等和程序实例关联起来,我们需要在构造文件中导入这些模块。因为这些模块也需要从构造文件中导入程序实例,所以为了避免循环依赖,这些导入语句在构造文件的末尾定义。

从构造文件中导入变量时不需要注明构造文件的路径,只需要从包名称导入,比如导入在构造文件中定义的程序实例APP,可以使用from messageBoard import app。

Flask在通过FLASK_APP变量定义的魔窟开中寻找程序实例。所以在启动程序前,我们需要给.flaskenv(需要安装python-dotenv)中的环境变量FLASK_APP重新赋值,这里仅写出包名称即可:

messageBoard/.flaskenv:

FLASK_APP=messageBoard

Flask实战-留言板-安装虚拟环境、使用包组织代码的更多相关文章

  1. flask实战-留言板-Web程序开发流程

    Web程序开发流程 在实际的开发中,一个Web程序的开发过程要设计多个角色,比如客户(提出需求).项目经理(决定需求的实现方式).开发者(实现需求)等,在这里我们假设自己是一个人全职开发.一般来说一个 ...

  2. Flask实战-留言板-使用Bootstrap-Flask简化页面编写

    使用Bootstrap-Flask简化页面编写 扩展Bootstrap-Flask内置了可以快速渲染Bootstrap样式HTML组件的宏,并提供了内置的Bootstap资源,方便快速开发,使用它可以 ...

  3. Flask实战-留言板-使用Flask-DebugToolbar调试程序、Flask配置的两种组织形式

    使用Flask-DebugToolbar调试程序 扩展Flask-DebugToolbar提供了一系列调试功能,可以用来查看请求的SQL语句.配置选项.资源加载情况等信息.这些信息在开发时会非常有用. ...

  4. Flask实战-留言板-使用Faker生成虚拟数据

    使用Faker生成虚拟数据 创建虚拟数据是编写Web程序时的常见需求.在简单的场景下,我们可以手动创建一些虚拟数据,但更方便的选择是使用第三方库实现.流行的python虚拟数据生成工具有Mimesis ...

  5. flask实战-个人博客-虚拟环境、项目结构

    个人博客 博客是典型的CMS(Content Management system,内容管理系统),通常由两部分组成:一部分是博客前台,用来展示开放给所有用户的博客内容:另一部分是博客后台,这部分内容仅 ...

  6. Python Flask之留言板(无数据库)

    一个py文件,一个html文件,可以直接运行 py文件 from flask import Flask, request, render_template, redirect, url_for imp ...

  7. php+redis实战留言板(todolist)与互粉功能

    目的:通过留言板(todolist)与互粉功能,掌握php操作redis的方法 相关数据操作命令 1,keys * 查看数据库所有的key 2,type + key: 如 type uid     查 ...

  8. django实战-留言板

    对应github链接:https://github.com/pshyms/django/tree/master/liuyanban 第一天 1. 创建一个新项目后,新建一个应用程序 python ma ...

  9. Python 每日一练 | Flask 实现半成品留言板

    留言板Flask实现 引言 看了几天网上的代码,终于写出来一个半成品的Flask的留言板项目,为什么说是半成品呢?因为没能实现留言板那种及时评论刷新的效果,可能还是在重定向上有问题 或者渲染写的存在问 ...

随机推荐

  1. VMware workstation --虚拟机静态ip设置

    背景介绍 我在本机win10上安装VMware workstation软件,新建两台centos7虚拟机,最近在配服务,每天虚拟机重启后,ip总会变,服务配置文件又要修改,很麻烦,便需要将其ip由dh ...

  2. [LeetCode] K-th Smallest Prime Fraction 第K小的质分数

    A sorted list A contains 1, plus some number of primes.  Then, for every p < q in the list, we co ...

  3. AWS Nginx Started but not Serving AWS上Nginx服务器无法正常工作

    After install the Nginx on AWS instance, and visit your public ip address, you might see the followi ...

  4. Winform 关闭按钮

    问题:我希望树形导航目录窗体在打开一条记录后自动隐藏,然后再次点击主页面打开按钮的时候在自动显示,这样就能保证树形目录仍旧显示隐藏前的展开状态.这里遇到一个问题,就是点击窗体右上角的关闭按钮时,默认情 ...

  5. AS中jar包和aar包区别及导入导出

    发布时间:2018-01-18 来源:网络 上传者:用户 关键字: 导出 导入 区别 包和 aar jar 发表文章 摘要:jar包和aar包区别*.jar:只包含class文件与清单文件,不包含资源 ...

  6. ASP.NET Core 问题排查:Request.EnableRewind 后第一次读取不到 Request.Body

    实际应用场景是将用户上传的文件依次保存到阿里云 OSS 与腾讯云 COS ,实现方式是在启用 Request.EnableRewind() 的情况下通过 Request.Body 读取流,并依次通过 ...

  7. JAR包结构,META-INF/MANIFEST.MF文件详细说明[全部属性][打包][JDK]

    转载请注:[https://www.cnblogs.com/applerosa/p/9736729.html] 常见的属性 jar文件的用途 压缩的和未压缩的 jar工具 可执行的JAR 1.创建可执 ...

  8. javascript 表达式

    //    for(表达式1;表达式2;表达式3){//        循环体语句;//    }//    先执行表达式1,在执行2表达式,//        如果2表达式结果为false,退出循环 ...

  9. python基础2 数据类型、数据拼接、数据转换

    一.数据类型 1.字符串 字符串英文string,简写str,只要是被[单/双/三引号]这层皮括起来的内容,不论那个内容是中文.英文.数字甚至火星文.只要是被括起来的,就表示是字符串类型 如:prin ...

  10. LVS,Keepalived,HAproxy区别与联系

    LVS,Keepalived,HAproxy区别与联系 LVS 全称Linux Virtual Server,也就是Linux虚拟服务器,由章文嵩(现就职于于淘宝,正因为如此才出现了后来的fullna ...