03SQLALchemy外键约束

一,配置

1,SQLALchemy的配置单独使用config.py文件
2,满足如下要求:
#dialect+driver://username:password@host:port/database

具体说明如下:

# dialect:是数据库的实现,比如MySql,SQLlite,且转换为小写
# driver:对应的驱动,比如MySql的驱动是MySqldb
# username:连接数据库的用户名
# password:密码
# host:连接数据库的域名
# port:数据库监听的端口号
# database:是连接的数据库的名字,创建数据库语句为:
SQL语句:"""create database db_demo1(database_name) charset utf8"""

# 如果以上输出了1则说明SQLAlchemy能成功连接到数据库。

DIALECT = "mysql"
DRIVER = "mysqldb"
USERNAME = "root"
PASSWORD = '1234'
HOST = "127.0.0.1"
PORT = "3306"
DATABASE = "db_demo3"

SQLALCHEMY_DATABASE_URI="{}+{}://{}:{}@{}:{}/{}".format(DIALECT,DRIVER,USERNAME,PASSWORD,HOST,PORT,DATABASE)
"""指定一个名为SQLALCHEMY_DATABASE_URI的固定变量,注意是固定的写法"""
SQLALCHEMY_TRACK_MODIFICATIONS =False

3,在主程序中引用并配置:

#引用
from flask import Flask
from flask_sqlalchemy import  SQLAlchemy
import config

#配置
app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)

二,具体使用

1,数据库创建与删除

2,表的创建

class User(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(100),nullable=False)

class Article(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),nullable=False)
    content = db.Column(db.Text,nullable=False)

    author_id = db.Column(db.Integer,db.ForeignKey('user.id')) #后面跟表名
db.create_all() #创建后一定记得这一步

创建后用Navicat查看为:

创建两个空表后需要写入数据:

    # user1 = User(username="zy")
    # db.session.add(user1)
    # db.session.commit()
    #
    # user2 = User(username="ly")
    # db.session.add(user2)
    # db.session.commit()
    #
    # article1 = Article(title="zy1", content="zy1",author_id=1)
    # article2 = Article(title="zy2", content="zy2", author_id=1)
    # article3 = Article(title="ly1", content="ly1", author_id=2)
    # article4 = Article(title="ly2", content="ly2", author_id=2)
    # db.session.add(article1)
    # db.session.add(article2)
    # db.session.add(article3)
    # db.session.add(article4)
    # db.session.commit()

User模块下user表的结构应该是:

id username
1 zy
2 ly

Article模块下articler表的结构应该是:

id title content author_id
1 zy1 zy1 1
2 zy2 zy2 1
3 ly1 ly1 2
4 ly2 ly2 2

3,增删改查(这里代码没怎么修改,主要看黄字部分)

def hello_world():
    # 数据的增加:
    # article1 = Article(title="a",content="A")
    # db.session.add(article1)
    # # 数据的增删改查都是在“session”里做的,但是它和web中的“session”不一样。
    # db.session.commit()  #每一步的提交都不能忘记

    # 数据的查:
    # # select * from article where title = "aaa";
    # result = Article.query.filter(Article.title == "a")[0]
    # print(result.title,result.content)
    # # query来源于db.Model,查找都是基于query的。

    # 数据的改:
    # # 1,先把你要更改的数据查找出来
    # article1 = Article.query.filter(Article.title == "a").first()
    # # 2,吧这条数据,你需要的地方进行修改
    # article1.title = "new title"
    # # 3,做事务的提交
    # db.session.commit()

    #数据的删:
    # 1,把需要删除的数据查找出来
    article1 = Article.query.filter(Article.title == "a").first()
    # 2,把这条数据删除
    db.session.delete(article1)
    # 3,做事务的提交
    db.session.commit()

    return 'Hello World!'

4,外键约束

对于以下两个需求来讲,实现如下,这是属于常规的且不方便的做法:

# 方案一:
#     # 找到标题为“zy1”的文章的作者
#     result1 = Article.query.filter(Article.title == "zy1").first()
#     result2 = User.query.filter(User.id == result1.author_id).first()
#     print(result2.username)
#
#     # 找到zy用户写过的所有文章
#     result3 = User.query.filter(User.username == "zy").first()
#     result4 = Article.query.filter(Article.author_id == result3.id).all()  #all
#     for i in result4:
#         print(i.title)

可以看到二.2部分只有一个单纯的外键关系(“author_id = db.Column(db.Integer,db.ForeignKey('user.id')) #后面跟表名”),对于上述两个操作不太方便,那么我们如何让上述操作更简单呢?

就在原源代码上加入黄代码那句:

class User(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(100),nullable=False)

class Article(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),nullable=False)
    content = db.Column(db.Text,nullable=False)

    author_id = db.Column(db.Integer,db.ForeignKey('user.id')) #跟表名

    author = db.relationship('User', backref=db.backref('articles'))  #后面跟模块名
  # 给“Article”这个模型添加一个“author”属性,可以访问这篇文章的作者的数据,像普通访问一样。
  # “backref”是定义反向引用,是通过“User.articles”这个模型访问这个模型的所有文章。

db.create_all()

注意加入的黄代码会改变表结构,这时候需要重建表,即drop操作和create就行。

对于之前两个操作而言可以有如下简便且实用操作,下面代码黄色部分重点关注

# 方案二
    # 找到标题为“zy1”的文章的作者(与下面的一段反向对应。)。
    # article = Article.query.filter(Article.title == "zy1").first()
    # print(article.author.username)

    # 找到zy用户写过的所有文章
    user = User.query.filter(User.username == "zy").first()
    result = user.articles  #这里的result是返回的所有文章,所以是个list类型,这就是backref带来的反向引用的作用
    print("{}的文章:".format(user.username))
    for i in result:
        print(i,"Title:",i.title,"Content:",i.content)

相当于在Article模块中从A表变为B表:

  • A表:
id
title
content
author_id
 
  • B表:

是是

id
title
content
author_id
author (=db.relationship('User', backref=db.backref('articles'))  #后面跟模块名)

===============================================================================

补充说明:

在一对多关系中,一个作者可以有多个文章。如图:

代码如下:

class Article(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),index=True)
    body = db.Column(db.Text)

class Author(db.Model):
    __tablename__ = "author"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(100),unique=True)
    phone = db.Column(db.String(11))

db.create_all()

那么我们需要分以下两个方面创建这种关系。

1,定义外键

因为外键只能存储
单一数据(标量),所以外键总是在这一侧定义, 多篇文章属于同一个作者, 所以我们需要为每篇文章添加外键存储作者的主键值以指向对应的作者。

分析过程:为什么定义在“这一侧?如果在作者里定义一个外键article_id,则表示这个作者只能有一篇文章;如果在文章里定义一个外键author_id,则表示这个文章只能有一个作者。

故在Article模型中, 我们定义一个author_id字段作为外键:

class Article(db.Model):
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('author.id'))

 2,定义关系属性

关系属性在一对多关系的这一侧。 一个作者拥有多篇文章,在Author模型中, 我们定义了一个articles属性来表示对应的多篇文章:

class Author(db.Model):
    ...
    articles = db.relationship('Article')

这个代码可以利用反向引用backref来写成:

class Article(db.Model):
    ...
    author = db.relationship('Author', backref=db.backref('articles'))

 关于backref的用法可以为自动在另一侧简历关系属性:

最终代码:

class Article(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),index=True)
    body = db.Column(db.Text)
    author_id = db.Column(db.Integer,db.ForeignKey('author.id'))
    author = db.relationship('Author', backref=db.backref('articles'))   #1号代码,与2之间只能存在一个。


class Author(db.Model):
    __tablename__ = "author"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(100),unique=True)
    phone = db.Column(db.String(11))
    articles = db.relationship('Article')  #2号代码,与1之间只能存在一个。

db.create_all()

 另外注意两点:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db = SQLAlchemy(app)

class Article(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    title = db.Column(db.String(100),index=True)
    body = db.Column(db.Text)
    author_id = db.Column(db.Integer,db.ForeignKey('author.id'))
    author = db.relationship('Author', backref=db.backref('articles'))   #1号代码,与2之间只能存在一个。


class Author(db.Model):
    __tablename__ = "author"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(100),unique=True)
    phone = db.Column(db.String(11))
    # articles = db.relationship('Article')  #2号代码,与1之间只能存在一个。

db.create_all()

@app.route('/')
def hello_world():
    foo = Author(name="Foo")
    db.session.add(foo)
    db.session.commit()
    spam = Article(title="Spam")
    ham = Article(title="Ham")
    db.session.add(spam)
    db.session.add(ham)
    db.session.commit()

    spam.author_id = 1
    db.session.commit()

    foo.articles.append(ham) #注意一:append
    db.session.commit()

    foo.articles.remove(spam) #注意一:remove
    db.session.commit()

    author1 = Author.query.filter(Author.name == "Foo").first()
    result = author1.articles  #注意二:这里的result是返回的所有文章,所以是个list类型
    for i in result:
        print("Foo的文章:",i,"Title:",i.title)

    return 'Hello World!'


if __name__ == '__main__':
    app.run()

=============================================================================

另外多对一,多对多的关系下次加

原文地址:https://www.cnblogs.com/two-peanuts/p/10718805.html