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从入门到做出一个博客的大型教程(三) 的相关文章

  • SQLAlchemy 关系错误:对象没有属性“c”

    I used sql自动编码 https code google com p sqlautocode 生成我的模型和所有关系 我正在尝试做一个简单的查询 例如 obj session query Venue filter Venue sym
  • 如何优化这个MySQL慢(非常慢)查询?

    我有一个 2 GB 的 mysql 表 包含 500k 行 我在没有负载的系统上运行以下查询 select from mytable where name in n1 n2 n3 n4 bunch more order by salary
  • Azure 部署未安装requirements.txt 中列出的Python 包

    这是我第一次将 Flask Web 应用程序部署到 Azure 我跟着这个tutorial https azure microsoft com en us documentation articles web sites python cr
  • 只获取倒数第二条记录 - mysql-query

    我有一个如下表记录 my table id rating description 1 0 0 bed 2 1 0 good 3 0 0 bed 4 1 0 good 5 0 0 bed 6 0 0 bed 7 0 0 bed 现在我通过评级
  • mysql转储到derby

    我正在使用 derby 在 eclipse 中进行开发 是否可以从 MySQL 转储表并以某种方式将其用于 derby 我知道 ddl 和 dml 对于两个 dbms 来说是不同的 但我正在寻找一种除了转储 导出之外的合适方法 我可以找到两
  • PHP PDO 使用 bindParam 第一个参数(不带冒号)[重复]

    这个问题在这里已经有答案了 请检查这个 user id int GET user id sql DELETE FROM users WHERE user id user id query db gt prepare sql query gt
  • SQL Join 列上类似于另一列[重复]

    这个问题在这里已经有答案了 可能的重复 mysql连接查询使用like https stackoverflow com questions 1930809 mysql join query using like 我想要进行连接 其中一列包含
  • 如何在 MySQL 中测试 Select for Update

    我正在表演SELECT FOR UPDATE或 InnoDB 表的行级锁定 我的目的是只有一个请求可以读取同一行 因此 如果两个用户同时请求相同的数据 其中只有一个人获取数据 即第一个触发查询的人 但是我如何测试锁定是否已放置 因为我正在通
  • mysql 中的二进制、十六进制和八进制值

    我对在 mysql 数据库中使用二进制 十六进制和八进制系统非常感兴趣 首先 请给我一个建议 为什么我们在存储信息时需要它们 因为信息太多 或者为什么 另外 哪种类型的值必须存储在标记系统中 另外这里还有像 这是例子 gt SELECT 5
  • 非常大的字段会对 MySQL 数据库产生负面影响吗?

    我目前正在使用 Django 构建一个网站 并希望托管用户生物样式页面 该页面可能长达几 KB 这些字段不一定需要搜索 但在查找用户名时确实需要提供 将这些数据存储在数据库中会产生负面影响吗 如果我使用带有数据库链接的静态文本文件 我的服务
  • ORDER BY 字段内的 MySQL 子查询。 (没有内连接)

    有很多与此相关的问题 但都具有使用内部联接的相同答案 这 我认为 在这里是不可能的 如果我错了请告诉我 我现在正在做的是调用两个不同的 mysql 查询来获取结果 它工作完美 db gt query SELECT FROM meta WHE
  • PHP MySql 百分比

    我的问题是关于百分比 我不是专家 所以我会尽力以更好的方式进行解释 我的 mysql 服务器中有一个表 假设有 700 条记录 如下所示 Name country language Birth Lucy UK EN 1980 Mari Ca
  • Mysql用in语句限制

    我正在写一个查询 SELECT user bookmarks id as user bookmark id bookmark id user bookmarks user id bookmark url bookmark website b
  • posts_search 中的自定义查询

    如何使用此查询作为我的自定义搜索查询 add filter posts search my search is perfect 20 2 function my search is perfect search wp query sWord
  • SQL查询查找表的主键?

    我怎样才能找到哪一列首要的关键使用查询来创建表 这是重复的question https stackoverflow com questions 893874 mysql determine tables primary key dynami
  • MYSQL从每个类别中随机选择一条记录

    我有一个数据库Items表看起来像这样 id name category int 有几十万条记录 每个item可以是 7 种不同的之一categories 对应于categories table id category 我想要一个从每个类别
  • 在 Celery 任务中调用 Google Cloud API 永远不会返回

    我正在尝试拨打外部电话Google Cloud Natural Language API从一个内Celery任务 使用google cloud python包裹 问题是对 API 的调用永远不会返回 挂起 celery task def g
  • 从Django中具有外键关系的两个表中检索数据? [复制]

    这个问题在这里已经有答案了 This is my models py file from django db import models class Author models Model first name models CharFie
  • Mysql插入表后不显示右单引号(’)

    我有一个名为 测试 的表 我插入了一行 其中包含unicode字符右单引号 0x2019在名称字段中 SQL insert into Testing values Sno Name Address insert into Testing v
  • 导入错误:没有名为flask.ext.login的模块

    我的flask login 模块有问题 我已经成功安装了flask login模块 另外 从命令提示符我可以轻松运行此脚本 不会出现错误 Python 2 7 r27 82525 Jul 4 2010 07 43 08 MSC v 1500

随机推荐

  • 使用微信小程序连接到 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