上篇文章学习了Flask框架——数据库操作命令(查询、修改、删除、添加),这篇文章我们学习Flask框架——模型关系(一对多关系)。
在一个完整的系统中,数据库、数据表是必不可少的,数据表与表之间有着一定的联系,互相影响着,而Flask框架与数据库有关的是模型,那么如何使模型之间产生联系呢。模型之间有两种关系:一对多、多对多。
在讲解模型之间关系前,首先我们创建一个Flask项目,其目录如下所示:
创建好项目后,我们开始编写配置文件settings.py的代码,如下所示:
class Configs:
ENV='development'
DEBUG=True
# 设置连接数据库路径
SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:123456@127.0.0.1:3306/test'
# 每次请求结束后自动提交数据库中的改动
SQLALCHEMY_COMMIT_ON_TEARDOWN=True
# 禁用SQLAlchemy对追踪对象的修改并且发送信号
SQLALCHEMY_TRACK_MODIFICATIONS = False
编写好配置文件后,我们将配置文件导入app.py文件中,代码如所示:
from flask import Flask
from settings import Config
app = Flask(__name__)
app.config.from_object(Config) # 加载配置
if __name__ == '__main__':
app.run()
好了,Flask框架的基础配置已经写好了,接下来我们将正式学习模型关系(一对多关系)。
一对多关系
我们拿用户与文章为例子,一个用户可以发布多篇文章,所以它们是一对多关系,我们假设数据库中用户表与文章表如下图所示:
这里我们在文章表中增加一个user_id字段来标志是哪个用户发表的文章,当我们想要找出张三所发表的所有文章时,只需要在文章表中搜索user_id为001的数据并输出即可。
在数据库中,数据表是这样设计,那么如何使模型之间产生联系呢,如何编写模型之间产生联系的代码呢?
ForeignKey外键
要想数据表产生联系,主外键是必不可少的,在Flask框架中,可以通过ForeignKey方法在模型类中设置外键,这里我们在文章Article模型类中设置外键,代码如下所示:
from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy(app=app,use_native_unicode="utf8") # 创建映射对象db
class Article(db.Model):
__tablename__ = 'article' #数据表名
id=db.Column(db.Integer,primary_key=True,autoincrement=True) #文章id为主键,自增
title=db.Column(db.String(50),nullable=False) #文章标题title
content=db.Column(db.Text,nullable=False) #文章内容content
click_num=db.Column(db.Integer,default=0) #文章点击数click_num,默认值为0
user_id=db.Column(db.Integer,db.ForeignKey('user.id'),nullable=False) #设置user_id字段为user数据表的外键
我们使用db.ForeignKey()方法将user_id字段设置为user数据表的外键,其方法传入的参数为产生联系的模型类数据表中的主键,注意:在一对多关系中,外键是设置在多的那方。
这样article数据表与user数据表产生了联系,那么是不是这样就可以了呢?答案是:不是。
relationship()方法
有了外键后,还需要使用relationship()让模型类之间产生联系,这里我们在User用户模型类中使用relationship()方法,代码如下所示:
class User(db.Model):
__tablename__ = 'user' #数据表名
id=db.Column(db.Integer,primary_key=True,autoincrement=True) #文章id为主键,自增
username=db.Column(db.String(15),nullable=False) #用户名username
password=db.Column(db.String(64),nullable=False) #用户密码password
phone=db.Column(db.String(11),unique=True) #用户手机号phone
isdelete=db.Column(db.Boolean,default=False) #字段isdelete,用来判断用户是否被删
articles=db.relationship('Article',backref='user',lazy='dynamic') #设置articles,其作用为使User模型类与其他模型类产生联系
我们使用了db.relationship()方法将该模型类与其他模型类产生联系。其中:第一个参数为你要产生联系的模型类,这里我们要产生联系的模型类为Article ;第二个参数backref为反向引用,其参数值可以是任意的,我们通过该参数值调用Article里面的属性字段;第三个参数lazy为数据加载,其参数值可以为:
- select:默认值,SQLAlchemy 会使用一个标准的 select 语句必要时一次加载数据;
- joined:告诉 SQLAlchemy 使用 JOIN 语句作为父级在同一查询中来加载关系;
- subquery:类似joined,但是SQLAlchemy会使用子查询;
- dynamic:在有多条数据的时候是特别有用的,不是直接加载这些数据,SQLAlchemy会返回一个查询对象,在加载数据前我们可以过滤(提取)它们。
一般情况下,lazy参数值我们会选择默认值,也就是说我们不需要写lazy参数。
注意:
- articles字段不会在数据表中体现出来,articles字段主要作用于模板与视图函数;
- db.relationship()只能定义在两个要互相关联的模型类中任意一个模型类。
查看数据表
好了,模型类的代码已经写好了,接下来我们通过编写代码创建数据表,其代码如下所示:
if __name__ == '__main__':
db.create_all() #创建数据表
app.run()
在终端执行app.py文件后,就成功创建好数据表了。下面我们在终端看看user、article数据表,如下图所示:
可以发现在user数据表中,没有articles字段,该字段是使用了db.relationship()方法,而不是使用db.Column()方法,所以不会在数据表中展示该字段,该字段作用是使模型类与模型类之间产生联系。
是不是模型关系——一对一关系就讲完了呢?NO,NO,NO,为了大家更直观地感受模型关系——一对一关系,我们通过编写代码使用模板来演示。
实例演示
添加文章数据
首先我们在app.py文件中创建一个视图函数,用来添加文章数据,代码如下所示:
@app.route('/publish',methods=['GET','POST'])
def article():
if request.method=='POST': #当请求为POST请求时
title=request.form.get('title') #获取请求中的title
content=request.form.get('content') #获取请求中的content
uid=request.form.get('uid') #获取请求中的uid
article=Article() #创建文章模型类实例对象
#将获取到的title、content、uid数据传递到实例对象article的title、content、user_id中
article.title=title
article.content=content
article.user_id=uid
#将获取到的数据保存在article数据表中
db.session.add(article) #添加数据
db.session.commit() #提交事务
return '添加成功'
else:
#当不是POST请求时
users=User.query.filter(User.isdelete==False).all() #找出所有user数据表中isdelete为False的数据
return render_template('add_article.html',users=users) #通过render_template()方法渲染add_article.html并传递users到网页中
编写好视图函数后,接下来在templates文件夹中创建一个名为add_article的html文件,其代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加文章</title>
</head>
<body>
<form action="{{ url_for('article') }}" method="post">
<p><input type="text" name="title" placeholder="文章标题"></p>
<p>
<textarea cols="50" rows="10" placeholder="输入文章内容" name="content"></textarea>
</p>
<p>
用户:
<select name="uid">
<option value="0">请选择用户</option>
{% for user in users %}
<option value="{{ user.id }}">{{ user.username }}</option>
{% endfor %}
</select>
</p>
<p><input type="submit" value="添加文章"></p>
</form>
</body>
</html>
在运行我们Flask项目前,我们先在user添加几条数据,如下图所示:
添加数据后,我们在终端执行app.py,并在浏览器中打开http://127.0.0.1:5000/publish,如下图所示:
当我们点击添加文章时,就会显示添加成功,添加成功后,我们再添加几条数据,如下图所示:
好了,成功添加文章后,那么我们如何在网页中展示文章标题、文章内容以及作者名呢?在article数据表中是没有作者名的,只有user_id,那么如何获取到作者名呢?
通过文章获取作者名
通过文章获取作者名,首先我们在app.py文件中编写视图函数,代码如下所示:
@app.route('/all_article')
def all_article():
articles=Article.query.all() #查询所有文章数据
return render_template('all_article.html',articles=articles) #通过render_template()方法渲染all_article.html并传递articles到网页中
编写好视图函数后,接下来在templates文件夹中创建一个名为all_article的html文件,其代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 获取文章数据列表 #}
{% for article in articles %}
<div id="container">
<p>
<h2>{{ article.title }}</h2>
<div>作者:{{ article.user.username }}</div>
</p>
<p>{{ article.content }}</p>
</div>
{% endfor %}
</body>
</html>
首先我们通过视图函数传递的articles获取到文章列表,再通过articles遍历获取文章内容与标题,注意第十二行代码,刚才我们在想如何获取作者名,在编写用户模型类时添加了articles字段,其代码如下所示:
articles=db.relationship('Article',backref='user',lazy='dynamic')
这个反向引用backref参数值user就很用有了,我们通过article.user获取user模型类对象,这样就有了user的属性了,再通过.username获取user中的username属性,这个属性也就是作者名了,在终端执行app.py,并在浏览器中打开http://127.0.0.1:5000/all_article,如下图所示:
这样我们成功获取到了文章标题、内容、作者名。
通过作者找出其文章
问题来了,当我们通过作者来找出其所有文章数据,该如何编写代码呢?
首先我们创建一个视图函数,代码如下所示:
@app.route('/author')
def author():
id=request.args.get('id') #获取请求的id号
user=User.query.get(id) #找出请求id的用户数据
return render_template('author.html',user=user) #通过render_template()方法渲染author.html并传递user到网页中
编写好视图函数后,接下来在templates文件夹中创建一个名为author的html文件,其代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 获取文章数据列表 #}
{% for article in user.articles %}
<div id="container">
<p>
<h2>{{ article.title }}</h2>
<div>作者:{{ user.username }}</div>
</p>
<p>{{ article.content }}</p>
</div>
{% endfor %}
</body>
</html>
该模板author.html文件与通过文章获取作者名的all_article.html文件类似,只是第八行和第十二行代码发生了改变。
第八行代码,将视图函数传递的user中.articles获取文章数据对象,获取到文章数据对象后就有了该对象的属性,这个articles就是我们User模型类中的articles字段,user.articles返回的是文章数据列表,第十二行代码直接通过user.username获取到用户名。
在终端执行app.py,并在浏览器中打开http://127.0.0.1:5000/author?id=1,如下图所示:
这里我们获取了用户id为1,也就是用户名为zhangsan的文章数据。
好了,Flask框架——模型关系(一对多关系)的相关知识就讲到这里了,下篇文章继续Flask框架——模型关系(多对多关系),感谢观看!!!
公众号:白巧克力LIN
网友评论