vlambda博客
学习文章列表

解决Flask-SQLAlchemy循环引用

10290

解决Flask-SQLAlchemy循环引用

1.问题

新建一个flask项目,它的初始化项目为:

$ tree
circular_references
├── app.py                    # 主 app 文件
├── static         #  css,js 文件目录
└── templates              # 模板文件目录

为了项目的健壮性,可以把flask的配置文件写入一个文件中config.py

此时实现一个如下的文件结构

$ tree
circular_references
├── app.py                          # 主 app 文件
├── config.py      # Flask 配置文件
├── static                              #  css,js 文件目录
└── templates                     # 模板文件目录

config.py

DEBUG = True  # 开启Debug
TEMPLATES_AUTO_RELOAD = True # 模板自动加载
DB_URI = 'mysql+pymysql://root:[email protected]:3306/flask_alembic_demo' # 确保数据库存在
# 指定数据库连接
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False

app.py

from flask import Flask
import config
from flask_sqlalchemy import SQLAlchemy


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

db = SQLAlchemy(app)

class User2(db.Model):
    __tablename__ = 'user2'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    name = db.Column(db.String(20))
    # 创建数据库关系, 双向联系
    addresses = db.relationship('Address2', back_populates='user')


class Address2(db.Model):
    __tablename__ = 'address2'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    email_address = db.Column(db.String(45), nullable=False)
    u_id = db.Column(db.Integer, db.ForeignKey('user2.id'))
    # 创建数据库关系, 双向联系
    user = db.relationship('User2', back_populates='addresses')


@app.route('/')
def hello_world():
    return 'Hello World!'


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

随着项目的不断壮大,不可能把所有的SQLAlchemy Model 都写入到app.pyapp 文件中,这时候就需要独立出一个文件专门存放Modelmodels.py

circular_references
├── app.py                          # 主 app 文件
├── config.py      # Flask 配置文件
├── models.py     # 存放flask-sqlalchemy.Model 类
├── static                              #  css,js 文件目录
└── templates                     # 模板文件目录

这时候需要修改app.py和新建models.py文件.

models.py

# models.py

from app import app
from flask_sqlalchemy import SQLAlchemy
db = SQlAlchemy(app)

class User2(db.Model):
    __tablename__ = 'user2'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    name = db.Column(db.String(20))
    # 创建数据库关系, 双向联系
    addresses = db.relationship('Address2', back_populates='user')


class Address2(db.Model):
    __tablename__ = 'address2'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    email_address = db.Column(db.String(45), nullable=False)
    u_id = db.Column(db.Integer, db.ForeignKey('user2.id'))
    # 创建数据库关系, 双向联系
    user = db.relationship('User2', back_populates='addresses')
# app.py

from flask import Flask
import config
from flask_sqlalchemy import SQLAlchemy
# 引入 User2,Address2
from models import User2,Address2

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

db = SQLAlchemy(app)

@app.route('/')
def hello_world():
  return 'Hello World!'

# 假设需要一个与数据库交互的模板文件
@app.route('/add_user/')
def add_user():
    """引用ORM交互"""
    u1 = User2(id=1, name='Jack')
    a1 = Address2(id=1, email_address='[email protected]', u_id=1)
    a2 = Address2(id=2, email_address='[email protected]', u_id=1)
    a3 = Address2(id=3, email_address='[email protected]', u_id=1)

u1.addresses = [a1, a2, a3]
db.session.add(u1)


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

如果执行运行app.py 文件,会产生一个循环引用 的报错

ImportError: cannot import name 'db' from 'app'

产生的原因很简单,python 代码是自上而下依次执行的.from models import user2 文件models.py 会先从app.py 中引入db ,才能生成User2 ,这就是循环引入

解决Flask-SQLAlchemy循环引用
10288

2.解决循环引入

为了解决他们之间的循环引入,这里需要引入第三个文件.

解决Flask-SQLAlchemy循环引用
10289

此时的目录结构如下

circular_references
├── app.py                          # 主 app 文件
├── config.py      # Flask 配置文件
├── models.py     # 存放flask-sqlalchemy.Model 类
├── ext.py        # 存放 db 
├── static                              #  css,js 文件目录
└── templates                     # 模板文件目录

ext.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# 不用绑定app,由 app.py 中绑定 app

models.py

# 从ext 中导入db
from ext import db

class User2(db.Model):
    __tablename__ = 'user2'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    name = db.Column(db.String(20))
    # 创建数据库关系, 双向联系
    addresses = db.relationship('Address2', back_populates='user')


class Address2(db.Model):
    __tablename__ = 'address2'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    email_address = db.Column(db.String(45), nullable=False)
    u_id = db.Column(db.Integer, db.ForeignKey('user2.id'))
    # 创建数据库关系, 双向联系
    user = db.relationship('User2', back_populates='addresses')

app.py

from flask import Flask
import config
# 引入db
from ext import db
# 引入 User2,Address2
from models import User2,Address2

app = Flask(__name__)
app.config.from_object(config)
# 利用init_app()方法绑定app
db.init_app(app)


@app.route('/')
def hello_world():
  return 'Hello World!'

# 假设需要一个与数据库交互的模板文件
@app.route('/add_user/')
def add_user():
    """引用ORM交互"""
    u1 = User2(id=1, name='Jack')
    a1 = Address2(id=1, email_address='[email protected]', u_id=1)
    a2 = Address2(id=2, email_address='[email protected]', u_id=1)
    a3 = Address2(id=3, email_address='[email protected]', u_id=1)

    u1.addresses = [a1, a2, a3]
    db.session.add(u1)


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

由于python自上而下执行,到执行User2() 函数时,它执行的是绑定appdb .

wechat
- END -
点击左下角查看更多

Flask学习笔记 发起了一个读者讨论 留言板: