缘起
在本系列的上一篇文章“Python Web开发学习(一):使用Flask框架”中,我们使用Flask框架开发了一个简单的Web应用程序,来显示一些城市的天气信息。但是这些天气信息都是写死在代码中的,如果我们有许多的天气信息,再写死在代码中就不太方便了。因此我们需要一个数据库来存储这些天气信息,然后从数据库中读取这些天气信息,再显示在网页上。
本文将介绍如何使用PostgreSQL数据库和SQLAlchemy操作数据库,来实现从数据库中读取天气信息。
前置条件
在开始本文之前,确保你已经清楚了如何用Flask框架开发一个简单的Web应用程序,如果不清楚,可以参考本系列的上一篇文章“Python Web开发学习(一):使用Flask框架”。
PostgreSQL
PostgreSQL简介
PostgreSQL是一个开源的关系型数据库管理系统,它的特点是功能强大、可扩展性好、支持SQL标准、支持事务、支持复杂查询、支持多种编程语言、支持多种操作系统。PostgreSQL是最流行的关系型数据库管理系统之一,因此这里我们选择使用PostgreSQL数据库来作为Web应用后端的数据库。
安装配置PostgreSQL
-
在Ubuntu 22中安装PostgreSQL非常简单,只需要在终端中运行以下命令即可:
1
sudo apt install postgresql
-
使用下面的命令可以查看安装的PostgreSQL的版本:
1
psql --version
-
安装好之后,PostgreSQL会自动创建一个名为
postgres
的用户,这个用户是超级用户,可以用来管理数据库。我们可以使用下面的命令来切换到postgres
用户:1
sudo su postgres
登录后我们以
postgres
用户的身份登录到系统的命令后中。然后运行下面的命令来登录到PostgreSQL数据库:1
psql
下面是PostgreSQL中常用的命令:
\l
:列出所有的数据库\?
:列出所有的命令\c <database_name>
:连接到指定的数据库\d
:列出当前数据库中的所有表\d <table_name>
:列出指定表的结构\q
:退出PostgreSQL\du
:列出所有的用户\du+
:列出所有的用户和用户的详细信息\password <user_name>
:修改指定用户的密码\conninfo
:显示当前连接的数据库信息
-
使用
\du
列出所有用户,可以发现目前只有一个用户postgres
。我们需要创建一个新的用户,用来管理我们的数据库。使用下面的命令创建一个新的用户:1
CREATE USER test WITH PASSWORD 'test_password';
这里的
test
是用户名,test
是密码。然后使用下面的命令给这个用户授予超级用户权限:1
ALTER USER test WITH SUPERUSER;
然后使用下面的命令退出PostgreSQL:
1
\q
然后使用下面的命令退出
postgres
用户:1
exit
-
然后我们重新用新建的用户
test
登录到PostgreSQL数据库:1
psql -U test
这时可能会遇到下面的报错信息:
1
FATAL: Peer authentication failed for user "test"
解决这个问题需要修改一下PostgreSQL的配置文件(参考https://zhuanlan.zhihu.com/p/467644334),使用下面的命令打开PostgreSQL的配置文件:
1
sudo vim /etc/postgresql/14/main/pg_hba.conf
其中
14
是PostgreSQL的版本号,如果你的版本号不是14
,请修改为你的版本号。在配置文件的最后可以看到这样的几行信息:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# Database administrative login by Unix domain socket local all postgres peer # TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all peer # IPv4 local connections: host all all 127.0.0.1/32 scram-sha-256 # IPv6 local connections: host all all ::1/128 scram-sha-256 # Allow replication connections from localhost, by a user with the # replication privilege. local replication all peer host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256
我们需要把
local all all peer
这一行的peer
改为md5
,然后保存退出。最后使用下面的命令重启PostgreSQL:1
sudo service postgresql restart
这时再重新尝试登录到PostgreSQL,就不会报错了:
1
psql -U test
-
最后为我们的Web应用创建一个新的数据库:
1
CREATE DATABASE weather_db;
这里的
weather_db
是数据库的名称。然后使用下面的命令退出PostgreSQL:1
\q
在Flask中使用PostgreSQL
安装psycopg2和SQLAlchemy
psycopg2是一个用于连接PostgreSQL数据库的Python库,SQLAlchemy是一个用于操作数据库的Python库。我们需要安装这两个库。先确保我们已经激活了Python虚拟环境,然后使用下面的命令:
|
|
创建数据库模型
-
在Flask应用中连接PostgreSQL数据库,使用下面的代码:
1 2 3 4 5 6 7
from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://test:test_password@localhost:5432/weather_db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app)
上面的代码中,我们首先导入
Flask
类和SQLAlchemy
类,然后创建一个Flask应用程序,然后使用app.config
来配置数据库的连接信息,其中SQLALCHEMY_DATABASE_URI
是数据库的连接地址,SQLALCHEMY_TRACK_MODIFICATIONS
是用来关闭对模型修改的监控,因为这个功能会消耗额外的内存,但是我们并不需要这个功能。最后我们创建一个db
对象,用来操作数据库。注意:这里的数据库使用端口号
5432
,这是PostgreSQL的默认端口号,如果你的PostgreSQL使用的端口号不是5432
,请修改为你的端口号。在PostgreSQL的配置文件中可以查看PostgreSQL使用的端口号。配置文件的路径是/etc/postgresql/14/main/postgresql.conf
,其中14
是PostgreSQL的版本号,如果你的版本号不是14
,请修改为你的版本号。 -
然后需要创建数据库模型,以在Flask中使用SQLAlchemy操作数据库。我们先导入
SQLAlchemy
库,然后创建一个db
对象,用来操作数据库。然后我们需要定义一个Weather
类,用来表示城市的天气信息。Weather
类继承自db.Model
类,这样Weather
类就可以使用db
对象来操作数据库。Weather
类有数个属性,和我们之前用字典定义的差不多。最后我们需要使用db.create_all()
方法来创建数据库表,这个方法会根据我们定义的数据库模型来创建数据库表。代码如下:1 2 3 4 5 6 7 8 9 10 11 12
db = SQLAlchemy(app) class Weather(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) country = db.Column(db.String(50), nullable=False) temp = db.Column(db.Integer, nullable=False) feels_like = db.Column(db.Integer, nullable=False) icon = db.Column(db.String(50), nullable=False) description = db.Column(db.String(50), nullable=False) db.create_all()
在应用中使用数据库
- 之前我们用字典来保存天气信息,现在我们改为用数据库来保存。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
db.session.add(Weather( name = 'London', country = 'UK', temp = '12', feels_like = '11', icon = '10d', description = 'Moderate rain' )) db.session.add(Weather( name = 'New York', country = 'US', temp = '20', feels_like = '19', icon = '01d', description = 'Sunny' )) db.session.commit()
- 然后我们需要从数据库中读取天气信息,然后传递给模板。注意,之前的HTML模板接收一个字典数组作为参数,现在我们需要传递一个
Weather
对象的数组,因此我们需要修改一下模板:Python中获取数据库数据并传递给模板的代码如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Weather App</title> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" type="text/css"> </head> <body> <section class="ajax-section"> <div class="container"> <ul class="cities"> {% for wd in weather_data %} <li class="city"> <h2 class="city-name">{{ wd.name }}, <sup>{{ wd.country }}</sup></h2> <div class="city-temp">{{ wd.temp }}<sup>°C</sup></div> <figcaption>{{ wd.description }}</figcaption> <img class="city-icon" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/162656/{{ wd.icon }}.svg" alt="{{ wd.description }}"> </li> {% endfor %} </ul> </div> </section> </body> </html>
这里的1 2
cities_data = Weather.query.all() return render_template('weather.html', cities_data=cities_data)
cities_data
是一个列表,列表中的元素是一个Weather
对象,我们可以在模板中使用这个对象的属性来获取天气信息。
运行Web应用程序
用下面的命令尝试运行我们的Web应用程序:
|
|
这时可能会遇到下面的报错信息:
|
|
这是因为我们的应用程序需要一个应用上下文,我们需要在app.py
中添加下面的代码:
|
|
最终的app.py
文件的代码如下:
|
|
然后我们再次运行应用程序:
|
|
不出意外的话,我们可以在浏览器中看到我们的网站在两个卡片里展示了两个城市的天气信息,和上一篇文章中的效果是一样的:
注意:每次运行应用程序时,都会向数据库中添加两条数据,因此如果多次运行应用程序,可能会导致数据库中有多条重复的数据,网页上也会出现多个重复的卡片。这时我们可以使用下面的代码来删除重复的数据:
|
|
总结
至此,我们成功创建了一个PostgreSQL数据库,然后在Flask应用程序中使用SQLAlchemy操作数据库。但是数据库中的数据仍然是我们一条一条手动添加的,这样是很不灵活也很不方便的。下一篇文章我们将介绍如何获取用户的输入,然后根据用户输入的城市使用API来获取天气信息,然后把获取到的天气信息保存到数据库中。