资讯专栏INFORMATION COLUMN

从零开始用 Flask 搭建一个网站(二)

Coly / 1609人阅读

摘要:从零开始用搭建一个网站一介绍了如何搭建环境,以及应用基本项目结构。我们要搭建的网站是管理第三方集成的控制台,类似于。我们先定义一个用户模型然后在文件夹下创建一个文件。

从零开始用 Flask 搭建一个网站(一) 介绍了如何搭建 Python 环境,以及 Flask 应用基本项目结构。我们要搭建的网站是管理第三方集成的控制台,类似于 Slack。 本篇主要讲解数据如何在 Flask 应用中流动,其它的框架基本上也是大同小异。

数据库

既然是数据的流动,首先要建立起存取数据的地方,也就是数据库了(这里是指关系型数据库,NoSQL 不在这讨论)。第一节中我们使用了 Flask-SQLAlchemy 管理数据库,在 Flask-SQLAlchemy 中,数据库使用 URL 指定,最流行的数据库 URL 格式如下:

在 config.py 中我们已经指定了数据库 URL,如果使用云平台部署程序,直接将生成的数据库 URL 写到 config.py 中 SQLALCHEMY_DATABASE_URI 即可。这里我们使用的是 SQLite 数据库。Flask-SQLAlchemy 采用数据库抽象层来操作数据库,也称为对象关系映射(Object-Relational Mapper, ORM),在用户不知不觉的情况下把高层的面向对象操作转换成低层的数据库指令,因此易用性好。我们已经在 app/__init__.py 中实例化了 SQLAlchemy 类:

app/__init__.py

from flask_sqlalchemy import SQLAlchemy
...
db = SQLAlchemy()
...

定义模型

模型类可以理解为数据库中的一张表,Flask-SQLAlchemy 提供了一个基类和一系列辅助类和函数来让我们定义模型的结构。我们直接在 app 文件夹下创建一个 models.py 文件。鉴于每个网站需求都不一样,所存的数据也不同,但本质上是大同小异的。这里以笔者网站需求为例,需要创建 Developer,Integration 和 Channel 三个表。

app/models.py 部分代码

from flask import current_app
from app import db

class Developer(db.Model):    
    __tablename__ = "developers"    
    id = db.Column(db.Integer, primary_key=True)    
    dev_key = db.Column(db.String(40), unique=True, index=True)    
    platform = db.Column(db.String(50))    
    platform_id = db.Column(db.String(40), unique=True)    
    username = db.Column(db.String(150), index=True)    
    integrations = db.relationship("Integration", backref="developer")    
    channels = db.relationship("Channel", backref="developer")

class Integration(db.Model):    
    __tablename__ = "integrations"    
    id = db.Column(db.Integer, primary_key=True)    
    integration_id = db.Column(db.String(40), unique=True)    
    name = db.Column(db.String(100))    
    description = db.Column(db.String(150))    
    icon = db.Column(db.String(150))    
    channel = db.Column(db.String(150))    
    token = db.Column(db.String(150))    
    developer_id = db.Column(db.Integer, db.ForeignKey("developers.id"))

class Channel(db.Model):    
    __tablename__ = "channels"    
    id = db.Column(db.Integer, primary_key=True)    
    developer_id = db.Column(db.Integer, db.ForeignKey("developers.id"))    
    channel = db.Column(db.String(150))    

    def __repr__(self):        
        return "" % self.channel

上面的每个 Class 都继承了 Model 类,因此每个类在数据库中都体现为一张表,表名用 tablename 表示,一般用复数形式。这里主要讲一下一对多的关系。可以看到上面 Developer 和 Integration 及 Channel 都有一个一对多的关系,一个用户可以有多个集成及多个频道。 看到这两句:

integrations = db.relationship("Integration", backref="developer")
developer_id = db.Column(db.Integer, db.ForeignKey("developers.id"))

第一句表明添加到 Developer 表的 integrations 属性表示这个关系的面向对象视角,对于一个 Developer 实例,integrations 属性将返回与 Developer 相关的所有 Integration,db.relationship() 第一个参数表明关系的另一端是哪个模型,backref 参数向 Integration 添加一个 developer 属性,从而定义反向关系。第二句是在 Integration 表中创建一个 developer_id 字段,这个字段被定义为外键,就是这个外键建立起了关系。传给 db.ForeignKey() 的参数 "developers.id" 表明这列的值是 developers 表中行的 id 值。另外,__repr__() 方法返回一个具有可读性的字符串表示模型,可以在调加粗文字试和测试时使用。下面我们就在命令行中操作一下数据库。
首先执行:

//创建 migrations 文件夹及相关文件
python manage.py db init

然后执行 :

//自动创建迁移脚本
python manage.py db migrate
//创建数据表或者升级到最新版本
python manage.py db upgrade

以后模型类有改动,比如删除或添加列,都要执行这两个命令,更新数据库表。现在在项目目录下应该自动生成了名为 dev 的数据库。
接下来执行如下命令进入 Python Shell:

python manage.py shell

创建表

使用 db.create_all() 就可以根据模型类创建表。如图:

使用 db.drop_all() 方法就可以删除所有的表,但是这种方式比较粗暴,所有的数据也一同销毁了。

插入行

以下命令在数据库表中插入了一条数据:

通过数据库会话 db.session 来管理对数据库所做的改动,在准备把对象写入数据库之前,首先要添加到会话中,然后用 commit() 方法提交会话。接下来我们继续插入一条 Integration 数据:

>>>from app.models import Integration,Channel
>>>integration = Integration(integration_id="i0001",name="github",description="first >>>application",channel="github_event",developer=developer)
>>> db.session.add(integration)
>>> db.session.commit()

注意上面的 developer 属性,正是我们在 models.py 中 Developer 模型中定义的一对多关系 integrations 属性的 backref 值, 所谓的反向关系即指在 Integration 表中每条数据都有一个 developer 属性指向 Developer 表中的某条数据,这是一对多关系的高级表示。现在可以用 developer.integrations 来查看该 developer 拥有的哪些集成,运行截图如下:

修改行

在提交数据库会话之前,改变对象的某个属性然后再提交即可更新行数据。如:

>>> developer.username = "lisi"
>>> db.session.add(developer)
>>> db.session.commit()

运行截图:

删除行

调用 db.session.delete() 方法即可删除行:

>>>db.session.delete(developer)
>>>db.session.commit()

查询行

Flask-SQLAlchemy 为每个模型提供了 query 对象,最基本的查询是返回表中的所有记录:

>>>Developer.query.all()

使用过滤器可以进行更精确的查询:

>>>Developer.query.filter_by(platform="qq").all()

如果你退出了 shell 会话,前面创建的对象就不会以 Python 对象的形式存在,而是作为各自数据库表中的行。这时需要重数据库中读取行,再重新创建 Python 对象,如:

>>> new_developer = Developer.query.filter_by(dev_key=12345).first()

注意上面的 first() 方法,如果不加上,将返回一个 BaseQuery 对象,这样就不能直接用 new_developer 来访问它的属性值。

在视图函数中操作数据库

上面介绍的所有数据库操作可以直接在视图函数中进行。假设我们要做一个简陋的注册功能,下面我们就来看看如何从网页中获取数据并保存在数据库中。我们先定义一个用户模型:

app/models.py

class User(db.model):
    __tablename__ = "users"
    id = db.column(db.Integer, primary_key=True)
    username = db.column(db.String(50), unique=True)
    password = db.column(db.String(100))

    def __repr__(self):
        return ""  % self.username

然后在 main 文件夹下创建一个 forms.py 文件。

app/main/forms.py

from flask_wtf import Form
from wtforms import StringField, SubmitField, PasswordField
from wtforms.validators import DataRequired

class UserForm(Form):      
    username = StringField("Input your username", validators=[DataRequired()])    
    password = PasswordField("Input your password", validators=[DataRequired()])    
    submit = SubmitField("Submit")

我们使用了 flask-wtf 扩展(pip install flask-wtf)来处理表单。
然后我们用在 index 页面中显示这个表单。

index.html

{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}注册{% endblock %}

{% block content %}
    {% for message in get_flashed_messages() %}    
        
{{ message }}
{% endfor %}
{{ wtf.quick_form(form) }}
{% endblock %}

现在回到 views.py 中,在我们的视图函数中作如下改动:

app/main/views.py

...
from .forms import UserForm
from ..models import User
from app import db


@main.route("/", methods=["GET", "POST"])
def signin():
    form = UserForm()
    if form is None:
        flash("Should input username and password")
    elif  form.validate_on_submit():
        user = User(username=form.username.data, password=form.password.data)
        db.session.add(user)
        try:
            db.session.commit()
            flash("User created !")
        except:
            db.session.rollback()
            flash("User create failed")
    return render_template("index.html", form=form)

接下来我们运行一下这个小试验:

python manage.py runserver

总结

本节我们介绍了在 Flask 中是如何使用 Flask-SQLAlchemy 、Flask-Migrate来管理数据库,并且示范了数据从网页储存到数据库的过程,这只是最基础的部分,下一节我们将探索如何在网页上发送请求并且得到数据,以及如何在页面之间传递数据。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/8964.html

相关文章

  • 从零开始 Flask 搭建一个网站(三)

    摘要:从零开始用搭建一个网站二介绍了有关于数据库的运用,接下来我们在完善一下数据在前端以及前端到后端之间的交互。在中有和两个函数,分别是请求成功和失败的回调函数。作者极光为极光团队账号,欢迎关注原文从零开始用搭建一个网站三知乎专栏极光日报 从零开始用 Flask 搭建一个网站(二) 介绍了有关于数据库的运用,接下来我们在完善一下数据在前端以及前端到后端之间的交互。本节涉及到前端,因此也会讲解...

    mykurisu 评论0 收藏0
  • 从零开始 Flask 搭建一个网站(四)

    摘要:前言从零开始用搭建一个网站三介绍了网页前端与后端前端与前端之间数据的交流。作者极光为极光团队账号,欢迎关注原文从零开始用搭建一个网站四知乎专栏极光日报 前言 从零开始用 Flask 搭建一个网站(三) 介绍了网页前端与后端、前端与前端之间数据的交流。本节主要介绍一下如何应用 Flask-OAuthlib, 使用 Flask-OAuthlib 就可以轻松地请求第三方应用提供的 API 。...

    CarterLi 评论0 收藏0
  • 从零开始搭建论坛(一):Web服务器与Web框架

    摘要:服务器通过协议与客户端通信,因此也被称为服务器。本文标题为从零开始搭建论坛一服务器与框架本文链接为更多阅读自己动手开发网络服务器一自己动手开发网络服务器二自己动手开发网络服务器三服务器网关接口实现原理分析最佳实践指南应用浅谈框架编程简介 之前用 Django 做过一个小的站点,感觉Django太过笨重,于是就准备换一个比较轻量级的 Web 框架来玩玩。Web.py 作者已经挂掉,项目好...

    dantezhao 评论0 收藏0
  • 从零开始搭建论坛():Web服务器网关接口

    摘要:在从零开始搭建论坛一服务器与框架中我们弄清楚了服务器应用程序框架的概念。框架应用生成状态码以及响应报头,然后将二者传递至,等待服务器保存。添加响应头,状态码返回响应信息创建一个服务器实例目前支持的成熟服务器有很多,是相当不错的一个。 在 从零开始搭建论坛(一):Web服务器与Web框架 中我们弄清楚了Web 服务器、Web 应用程序、Web框架的概念。对于 Python 来说,越来越多...

    Astrian 评论0 收藏0
  • 从零开始搭建论坛(三):Flask框架简单介绍

    摘要:我们的论坛项目就使用了该框架。此外,麦子学院也有一个入门视频教程,一共小时的视频教程,涵盖开发的方方面面,包括环境的搭建,语法介绍,项目结构的组织,全球化,单元测试等内容。博客地址更多阅读的机制三个框架的对比 前面两篇文章中我们已经了解 Web(HTTP)服务器,Web应用程序,Web框架,WSGI这些 Python Web 开发中的概念。我们知道,Web框架通过将不同Web应用程序中...

    Alan 评论0 收藏0

发表评论

0条评论

Coly

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<