Flask从入门到做出一个博客的大型教程(三)

2023-10-31

Flask从入门到做出一个博客的大型教程(三)

在开始之前,先来看下项目的整体结构。

flask
├── app
│   ├── forms.py
│   ├── __init__.py
│   ├── routes.py
│   └── templates
│       ├── base.html
│       ├── index.html
│       └── login.html
├── config.py
├── myblog.py

4 数据库

对于一个完整的网站数据库是很重要的,因为你的数据得有位置读取呀,网上很多数据库都用的sqlite,但是,我想使用mysql,所以接下来咱们就以mysql为数据库来讲解喽。

(venv) duke@coding:~/flask_tutorial/flask$ pip install flask-sqlalchemy

这样就可以对数据库进行操作了,但是实际项目中会经常对数据库进行修改,但是一般不会手动的去数据库里进行改动,通常的做法是修改ORM对应的模型,然后再把模型映射到数据库中。在flask里有一个集成的工具是专门做这个事情的,安装它。

(venv) duke@coding:~/flask_tutorial/flask$ pip install flask-migrate

因为我使用的是MySQL数据库,而在python3中不再支持mysqldb,因此我们还需要安装pymysql.

(venv) duke@coding:~/flask_tutorial/flask$ pip install pymysql

需要的组件都安装好了,接下来在配置文件里配置数据库。

app/config.py : 使用配置文件config.py中的内容

import os
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
class Config(object):
    #.......
    #格式为mysql+pymysql://数据库用户名:密码@数据库地址:端口号/数据库的名字?数据库格式
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:123456@localhost:3306/flaskblog?charset=utf8'
    #如果你不打算使用mysql,使用这个连接sqlite也可以
    #SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR,'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

配置文件设置好了以后,就要对初始化文件进行修改。

app/_ _ init_ _.py : 数据库的初始化设置

from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config.from_object(Config)
#建立数据库关系
db = SQLAlchemy(app)
#绑定app和数据库,以便进行操作
migrate = Migrate(app,db)

from app import routes,models

接下来比较重要的就是设计模型了,model是模型的映射,只有设计好model才能进行一系列的操作。新建一个models.py文件。

(venv) duke@coding:~/flask_tutorial/flask$ touch app/models.py

app/models.py : 用户数据库模型

from app import db

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(64),index=True,unique=True)
    email = db.Column(db.String(120),index=True,unique=True)
    password_hash = db.Column(db.String(128))

    def __repr__(self):
        return '<用户名:{}>'.format(self.username)

对模型进行验证:

(venv) duke@coding:~/flask_tutorial/flask$ python
Python 3.6.4 (default, May  3 2018, 19:35:55) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from app.models import User
>>> u = User(username='duke',email='duke@126.com')
>>> u
<用户名:duke>

对模型验证后,发现是正确的,进行数据库初始化。

(venv) duke@coding:~/flask_tutorial/flask$ flask db init
  Creating directory /home/duke/flask_tutorial/flask/migrations ... done
  Creating directory /home/duke/flask_tutorial/flask/migrations/versions ... done
  Generating /home/duke/flask_tutorial/flask/migrations/script.py.mako ... done
  Generating /home/duke/flask_tutorial/flask/migrations/alembic.ini ... done
  Generating /home/duke/flask_tutorial/flask/migrations/README ... done
  Generating /home/duke/flask_tutorial/flask/migrations/env.py ... done
  Please edit configuration/connection/logging settings in
  '/home/duke/flask_tutorial/flask/migrations/alembic.ini' before proceeding.

现在看一看项目结构

flask
├── app
│   ├── forms.py
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   └── templates
│       ├── base.html
│       ├── index.html
│       └── login.html
├── config.py
├── migrations
│   ├── alembic.ini
│   ├── env.py
│   ├── README
│   ├── script.py.mako
│   └── versions
├── myblog.py

接下来创建数据库的管理工具。

(venv) duke@coding:~/flask_tutorial/flask$ flask db migrate -m 'users_table'
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'user'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_user_email' on '['email']'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_user_username' on '['username']'
  Generating
  /home/duke/flask_tutorial/flask/migrations/versions/06ea43ff4439_users_table.py
  ... done

创建数据库的中的表。

(venv) duke@coding:~/flask_tutorial/flask$ flask db upgrade
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 06ea43ff4439, users_table

执行到这里,表已经在数据库中建立完成。或许你会问,这和我以前的接触过的不一样啊,这么会麻烦这么多,因为你对数据库模型修改后,可以很方便的进行数据库表的迁移,这会大大的减少以后可能会发生的大量的工作量。

网站里不可能只有一张表的,多张表之间肯定会有联系,接下来对表之间的关系进行一个详细介绍。

app/models.py : 添加一张新表,并建立关系

from datetime import datetime
from app import db

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(64),index=True,unique=True)
    email = db.Column(db.String(120),index=True,unique=True)
    password_hash = db.Column(db.String(128))
    # back是反向引用,User和Post是一对多的关系,backref是表示在Post中新建一个属性author,关联的是Post中的user_id外键关联的User对象。
    #lazy属性常用的值的含义,select就是访问到属性的时候,就会全部加载该属性的数据;joined则是在对关联的两个表进行join操作,从而获取到所有相关的对象;dynamic则不一样,在访问属性的时候,并没有在内存中加载数据,而是返回一个query对象, 需要执行相应方法才可以获取对象,比如.all()
    posts = db.relationship('Post',backref='author',lazy='dynamic')

    def __repr__(self):
        return '<用户名:{}>'.format(self.username)

class Post(db.Model):
    __tablename__ = 'post'
    id = db.Column(db.Integer,primary_key=True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime,index=True,default=datetime.utcnow)
    user_id = db .Column(db.Integer,db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post {}>'.format(self.body)

生成新的数据库关系:

(venv) duke@coding:~/flask_tutorial/flask$ flask db migrate -m 'posts_table'
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'post'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_post_timestamp' on '['timestamp']'
  Generating /home/miguel/microblog/migrations/versions/780739b227a7_posts_table.py ... done

提交到数据库中:

(venv) duke@coding:~/flask_tutorial/flask$ flask db upgrade
INFO  [alembic.runtime.migration] Context impl MySQLImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 780739b227a7, posts_table

接下来使用shell对进行操作:

(venv) duke@coding:~/flask_tutorial/flask$ python
Python 3.6.4 (default, May  3 2018, 19:35:55) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from app import db
>>> from app.models import User,Post

在用户表中添加一条用户信息:

#创建一个User对象实例
>>> u = User(username='duke',email='duke@126.com')
#将实例添加
>>> db.session.add(u)
#提交
>>> db.session.commit()

查看数据库后发现,插进一条数据。

在用户表中添加另外一条用户信息:

>>> u = User(username='king',email='king@qq.com')
>>> db.session.add(u)
>>> db.session.commit()

通过查询数据库发现也插进了一条数据,但是怎么查询的呢?

查询数据库中信息:

>>> users = User.query.all()
>>> users
[<用户名:duke>, <用户名:king>]
>>> for u in users:
...     print(u.id,u.username)
... 
1 duke
2 king

这是一次性全部查询,那能不能查单条数据呢?答案是肯定的喽。

#根据id可以查询到数据
>>> u = User.query.get(2)
>>> u
<用户名:king>

普通的数据库表咱们会了,那么有外键关联的一对多中数据库表怎么插入数据呢?

#查找到一个User对象
>>> u = User.query.get(1)
#将该User对象与Post建立关系
>>> p = Post(body='我第一次提交数据!',author=u)
>>> db.session.add(p)
>>> db.session.commit()
#插入第二条数据,但是拥有者都是同一个人
>>> p = Post(body='我第二次提交数据了!',author=u)
>>> db.session.add(p)
>>> db.session.commit()

现在通过查询来让你更加的熟悉一对多的关系。

# 获得一个用户的所有提交
>>> u = User.query.get(1)
>>> u
<用户名:duke>
#u.posts.all()中的posts是model中的,User和Post关联的作用。
>>> posts = u.posts.all()
>>> posts
[<Post 我第一次提交数据!>, <Post 我第二次提交数据了!>]

#进行相同的操作,但是换成另外一名用户
>>> u = User.query.get(2)
>>> u
<用户名:king>
>>> u.posts.all()
[]

#对所有的posts进行查询
>>> posts = Post.query.all()
>>> for p in posts:
...     print(p.id,p.author.username,p.body)
... 
1 duke 我第一次提交数据!
2 duke 我第二次提交数据了!

#还可以按照一定的规则进行查询
>>> User.query.order_by(User.username.desc()).all()
[<用户名:king>, <用户名:duke>]

熟悉了查询,接下来就把刚才的测试数据都删除吧!

>>> users = User.query.all()
>>> for u in users:
...     db.session.delete(u)
... 
>>> posts = Post.query.all()
>>> for p in posts:
...     db.session.delete(p)
... 
>>> db.session.commit()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flask从入门到做出一个博客的大型教程(三) 的相关文章

  • PHP多图像文件上传并存储到文件夹和数据库

    我正在建立一个网站 向夜间狂欢者展示大城市夜总会场所和活动的列表 我正在尝试构建一个后端页面 管理员可以在其中添加俱乐部并输入信息 例如机构名称 位置 相对价格等 当然还有俱乐部的一些图像 每个俱乐部必须至少有一张图像 即主图像 可以有额外
  • 连接 3 三张表

    我有这个图表应该可以解释我的情况 我需要一些关于连接 3 个表的帮助 我不知道如何做这种事情 因此 我可以通过执行以下操作来经历一段检索记录的 while 循环 img src alt Album AlbumID 使用内部联接 http w
  • PHP:如何检查总数。 URL 中的参数?

    我正在使用 REQUEST 检索参数 有没有办法找到总数 URL 中的参数 而不是检索每个参数然后进行计数 这将为您提供总数 分隔的 URL 查询参数 count explode SERVER QUERY STRING 如果您只想要唯一的参
  • 使用所有连接的 Flask unittest 和 sqlalchemy

    在进行了大约 100 个单元测试后 我刚刚在 Flask 应用程序上运行单元测试时遇到了问题 所有单元测试都会通过 但是当一次全部运行时 它们将失败并出现以下错误 OperationalError OperationalError FATA
  • Innodb页面大小设置

    在innodb中 页面大小默认为16kb 如何将页面大小设置为 8kb 是否有在源编译步骤中设置的选项 您不需要在源编译步骤中指定页面大小 MySQL 5 6 及更高版本支持不同的页面大小 无需重新编译 但是 您必须在初始化 InnoDB
  • 主键默认可以为NULL吗?为什么这样描述呢?

    我有一张桌子 当我describe这是 mysql gt DESC my table Field Type Null Key Default Extra contact id int 11 NO PRI NULL auto incremen
  • 使用 try {} catch {} 与 if {} else {} 相比有何优势

    我正在从 php 中的普通 mysql 切换到 PDO 并且我注意到测试错误的常见方法是使用 try catch 组合而不是 if else 组合 该方法的优点是什么 我可以使用一个 try catch 块而不是多个嵌套的 if else
  • MySQL SELECT OpenCarts 数据库中的重复行

    只是玩一下 OpenCart DB 看看我是否能学到一些东西 如果我使用以下SELECT结果返回重复的行 SELECT DISTINCT p product id AS pid p model AS modelo SUBSTRING p m
  • 连接两个表而不返回不需要的行

    我的表结构如下所示 tbl users tbl issues userid real name issueid assignedid creatorid 1 test 1 1 1 1 2 test 2 2 1
  • sqlalchemy 插入或更新的简单方法?

    我有一系列新对象 它们看起来都类似于 Foo pk col1 x pk col2 y val bar 其中一些是存在的 Foo 即只有 val 与数据库中的行不同 并且应该生成更新查询 其他人应该生成插入 我可以想到几种方法来做到这一点 最
  • 使用 Sequelize (NodeJS) 代替 * 指定特定字段

    好吧 我在 NodeJS 中有一个项目 我正在其中使用 Sequelize 来实现 MySQL ORM 这件事工作得非常好 但是我试图弄清楚是否有一种方法可以指定在查询的基础上返回哪些字段 或者是否有一种方法可以在某处执行 query 例如
  • MySQL,连接两列

    MySQL 表中有两列 SUBJECT and YEAR 我想生成一个字母数字唯一编号 其中包含主题和年份的串联数据 我怎样才能做到这一点 是否可以使用像这样的简单运算符 您可以使用CONCAT http dev mysql com doc
  • 如何使用Python3.4在tornado中进行异步mysql操作?

    我现在使用Python3 4 我想在Tornado中使用异步mysql客户端 我已经发现torndb https github com bdarnell torndb但在阅读其源代码后 我认为它无法进行异步mysql操作 因为它只是封装了M
  • Mysql 将 --secure-file-priv 选项设置为 NULL

    我在 Ubuntu 中运行 MySQL 我在运行特定的查询集时收到此错误 MySQL 服务器正在使用 secure file priv 选项运行 因此无法执行此语句 当我这样做的时候SELECT secure file priv 在我的 m
  • MySQL 薛定谔表:存在,但不存在

    我遇到了最奇怪的错误 有时 在创建或更改表时 我会收到 表已存在 错误 但是 DROP TABLE 返回 1051 未知表 所以我得到了一个无法创建 无法删除的表 当我尝试删除数据库时 mysql 崩溃了 有时它有助于创建另一个具有不同名称
  • 内连接 3 个表

    我正在使用 PHP 和 PDO 我需要重新收集连接 3 个表的信息 photos albums 相册照片 该表具有以下结构 photos photo id int path varchar nick varchar date timesta
  • MySQL 组合两个查询

    我有两个 MySQL 查询 QUERY SELECT sodnik 1 FROM prihodnji krog WHERE file id 8778 AND sodnik 1 UNION SELECT sodnik 2 FROM priho
  • DataTables 第 2 页的分页未调用放大弹出窗口

    所以我有这个启用分页的数据表 我编码了一种方式 以便用户可以编辑表的行 当用户调用它在放大弹出窗口中打开的编辑页面时 它在第 1 页 从第 2 页起都运行良好 DataTable 及其前面停止调用 Magnific Popup 我只是不明白
  • 蟒蛇 | MySQL | AttributeError:模块“mysql.connector”没有属性“connect”

    我正在学习 python 中的一个新库 mysql 我尝试执行以下命令 import mysql connector mydb mysql connector connect host localhost user root passwd
  • 带 Flask 的 RPI dht22:无法将第 4 行设置为输入 - 等待 PulseIn 消息超时

    我正在尝试制作一个 Raspberry Pi 3 REST API 使用 DHT22 提供温度和湿度 整个代码 from flask import Flask jsonify request from sds011 import SDS01

随机推荐

  • 使用微信小程序连接到 MQTT 云服务

    微信小程序是腾讯于 2017 年 1 月 9 日推出的一种不需要下载安装即可在微信平台上使用的应用程序 用户扫一扫或者搜一下即可打开应用 也体现了 用完即走 的理念 用户不用关心是否安装太多应用的问题 应用将无处不在 随时可用 但又无需安装
  • input-file 部分手机不能拍照问题

    曾经遇到一个需求 用户拍身份证上传验证 然后我卡在了拍照这个点上 最初采用的是微信的 api wx chooseImage 但随后发现 返回的是一种只有微信才能预览的 url 格式 但验证是要放在 PC 上进行的 等于保存了这个 url 也
  • uniapp省市区3级联动组件

    1 组件代码picker region vue
  • CDN 内容分发网络

    第一步 HTML的文件引用 HTML的文件头 也有文件中 文件尾 那边常有其他文件引用 比如CSS以及JS的引用 就以bootstrap常用的引用来举个栗子 你常见的引用可能会是这样的
  • MVN Scope属性说明

    MVN 的Scope属性包括 compile 默认配置 provided runtime system test compile compile是默认的范围 如果没有提供一个范围 那该依赖的范围就是编译范围 编译范围依赖在所有的classp
  • Web前端复习——Javascript(1)

    1 js发展进程关键词 ECMAScript标准 定义了js语言的核心语法 Netscape 遵照标准 实现了Javascript语言 Microsoft 遵照标准 实现了JSscript标准 W3C DOM标准 专门操作网页内容的标准 所
  • 算法基础--递归与回溯、递推、迭代关系

    递归的优缺点 优点 代码更简洁清晰 可读性更好 实际上递归的代码更清晰 但是从学习的角度要理解递归真正发生的什么 是如何调用的 调用层次和路线 调用堆栈中保存了什么 可能是不容易 但是不可否认递归的代码更简洁 缺点 由于递归需要系统堆栈 所
  • 微信小程序期末作业-优购商城

    优购商城微信小程序 2021下半年微信小程序期末作业 下载链接在文末 首页有轮播图 点我下载资源 https download csdn net download weixin 43474701 57893310
  • Visual Studio中如何进行多线程调试

    多线程的应用通常使得我们的程序调试变得困难和复杂 但是也是有章法可言的 在设计和开发多线程的程序时 需要考虑的就是多线程之间的资源共享和相互协作 资源共享和协作通常使用互斥量和信号量机制进行解决 我们在调试多线程程序时 不能把程序运行过程仅
  • 报错处理:org.xml.sax.SAXParseException: 不允许有匹配 “[xX][mM][lL]“ 的处理指令目标

    在vue项目中配置user xml文件后 重新启动后台报错 org xml sax SAXParseException 不允许有匹配 xX mM lL 的处理指令目标 后面查阅后发现 xml文件是从别处粘贴过来的 没有顶格写 这样 达咩 这
  • Nginx相关配置

    启动Nginx 到nginx sbin目录下 nginx 1 反向代理的配置一 打开浏览器 在浏览器的地址栏输入 www 123 com 跳转到Linux系统tomcat上 我们访问一个网址的时候 浏览器会先查询本地有没有缓存这个网址对应的
  • 计算机牛人找工作-----可以参考(9个offer,12家公司,35场面试,从微软到谷歌2012)

    http www kuqin com job 20130111 333954 html 1 简介 毕业答辩搞定 总算可以闲一段时间 把这段求职经历写出来 也作为之前三个半月的求职的回顾 首先说说我拿到的offer情况 微软 3面 gt 终面
  • SDN介绍

    随着通信技术的不断发展 SDN已经逐渐成为整个行业注目的焦点 很多人认为SDN技术必将对传统网络带来一次划时代的变革 那么 什么是SDN 我们有应该如何理解和学习SDN 我们为什么需要SDN SDN的实现方式有哪些 SDN的未来发展方向是什
  • Mac安装Redis

    要在Mac上安装Redis 你可以按照以下步骤进行操作 打开终端应用程序 Terminal 可以在 应用程序 文件夹的 实用工具 目录下找到它 或者command 空格 输入ter然后直接回车 确保你已经安装了Homebrew 如果没有 请
  • 解决kibana启动时:3005 - wrong protocol being used to connect to the wazuh api 和 Wazuh API seems to be dow

    解决elasticsearch缺少模板问题 https mp csdn net editor html 112570396 后 依然不能正常检测到 wazuh api 状态 默认ip和端口 现在 解决kibana启动时 3005 wrong
  • Git教程---Windows安装及命令使用(详细例子)

    目录 一 Git的工作原理 二 Git下载及安装 三 Git配置 四 Git命令 示例 参考链接 一 Git的工作原理 Git有四个工作区域 其中三个工作区域工作在本地 一个工作区域工作在远程仓库 本地目录 工作区 平时存放项目代码的位置
  • 使用 Grid 进行常见布局

    grid 布局是W3C提出的一个二维布局系统 通过 display grid 来设置使用 对于以前一些复杂的布局能够得到更简单的解决 本篇文章通过几个布局来对对 grid 布局进行一个简单的了解 目前 grid 仅仅只有 Edge使用前缀能
  • 【windows系统】通过SSH Key访问服务器

    BG 废话不多说 直接上干货 1 终端输入命令 ssh username server 确认是否有自己的用户名 2 查看是否生成过SSH Key ls ssh 未生成过 提示 No such file or directory 生成过 提示
  • 旅游推荐平台

    作者主页 编程千纸鹤 作者简介 Java 前端 Python开发多年 做过高程 项目经理 架构师 主要内容 Java项目开发 毕业设计开发 面试技术整理 最新技术分享 收藏点赞不迷路 关注作者有好处 文末获得源码 项目编号 BS XX 05
  • Flask从入门到做出一个博客的大型教程(三)

    Flask从入门到做出一个博客的大型教程 三 在开始之前 先来看下项目的整体结构 flask app forms py init py routes py templates base html index html login html