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. jquery提示sucess

    这是学习笔记. 今天做东西的时候,想把体验做好,于是打算再ajax success字段中添加函数实现提示sucess. 用了jquery的fadeIn 跟fadeOut,再fadeIn的callbac ...

  2. BOM 浏览器对象模型_XMLHttpRequest 对象

    XMLHttpRequest 对象 浏览器与服务器之间,采用 HTTP 协议 通信. 用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏览器就会向服务器发出 HTTP 请求 AJ ...

  3. Linux搭建git服务端

    1.安装$ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel$ yum inst ...

  4. org.apache.ibatis.binding.BindingException: Parameter 'start' not found. Available parameters are [1, 0, param1, param2]

    DEBUG 2018-05-30 08:43:26,091 org.springframework.jdbc.datasource.DataSourceTransactionManager: Roll ...

  5. 模块化Javascript代码的两种方式

    1.将模块整体放在函数里 function buildMonthNameModule() { var names = ["January ", "February&quo ...

  6. 学习ActiveMQ(五):activemq的五种消息类型和三种监听器类型

    一.前面我们一直发送的是字符串类型,其实activemq一共支持五种消息类型: 1.String消息类型:发送者:消费者: 1.String消息类型:发送者:消费者: 1.String消息类型:发送者 ...

  7. js基础--数据类型

    1,数据类型 Number:包括小数与整数,负数,NaN ,Infinity无限大String字符串:‘abc’Boolean布尔值:true or falsenull 空undefined 未定义 ...

  8. LeetCode 217 Contains Duplicate 解题报告

    题目要求 Given an array of integers, find if the array contains any duplicates. Your function should ret ...

  9. Python_tkinter(4)_上传文件

    1.上传单个文件 import tkinter as tk from tkinter import filedialog def upload_file(): selectFile = tk.file ...

  10. python pip出错问题解决记录

    今天安装一下requests模块,遇到网络问题 pip install requests Retrying (Retry(total=4, connect=None, read=None, redir ...