gpt4 book ai didi

python - lazy=True 在 (Flask-)SQLAlchemy 中

转载 作者:行者123 更新时间:2023-11-28 21:41:02 25 4
gpt4 key购买 nike

我正在学习 SQLAlchemy,我想确保我已正确理解 relationship 中的 backref 参数。

例如

from app import db

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True)

posts = db.relationship('Post', backref='author', lazy=True)


class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))

user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

假设我有一个用户对象 j = models.User.query.get(1)。我的问题是,下面的东西有什么区别吗?

  • j.posts
  • Post.query.filter_by(author=j).all()
  • Post.query.with_parent(j).all()
  • Post.query.with_parent(j, property='posts').all()
  • Post.query.with_parent(j, property=User.posts).all()

返回的结果是一样的,但不知道执行的SQL语句是否相同。

我尝试过的

SQLAlchemy docs说:

with_parent(instance, property=None, from_entity=None)

...the given property can be None, in which case a search is performed against this Query object’s target mapper.

所以最后三个语句看起来一样,但我真的不明白这个查询对象的目标映射器指的是什么。在这种情况下是 Post,因为此查询是在 Post 上执行的吗?

最佳答案

即使生成的 SQL 语句相同,您使用的命令也可能对您的应用程序产生不同的影响,例如j.posts 将缓存(memoize,不要与 Werkzeug 缓存混淆)您获得的结果,而其他人将每次获取它们。

如果您从查询中删除 .all(),您可以简单地打印它们:

query = Post.query.filter_by(author=j)
print(query)

这会导致:

SELECT post.id AS post_id, post.body AS post_body, post.user_id AS post_user_id 
FROM post
WHERE ? = post.user_id

使用 .all() 本质上就像获取 [m for m in query])。

查询打印的技巧不适用于 j.posts,它会返回如下内容:

> print(j.posts)
> [Post(...), Post(..)]

不过,您仍然可以使用内置的 sqlalchemy 记录器查看所有静默发出的查询。见以下代码:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.engine import Engine
from sqlalchemy import event
import logging


app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/tests.db'
db = SQLAlchemy(app)


logging.basicConfig()
logger = logging.getLogger('sqlalchemy.engine')


class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True)

posts = db.relationship('Post', backref='author', lazy=True)


class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))

user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

db.drop_all()
db.create_all()
user = User(username='test', posts=[Post(body='some body')])
db.session.add(user)
db.session.commit()

# start logging
logger.setLevel(logging.DEBUG)
j = User.query.get(1)

queries = {
"j.posts",
"Post.query.filter_by(author=j)",
"Post.query.with_parent(j)",
"Post.query.with_parent(j, property='posts')",
"Post.query.with_parent(j, property=User.posts)",
}

def test_queries():
for name in queries:
print('\n=======')
print('Executing %s:' % name)
query = eval(name)
print(query)

test_queries() # you should see j.posts query here
print('Second test')
test_queries() # but not here

回到您的问题:是的,发出的 SQL 查询是相同的。

查询对象的目标映射器中,查询对象的目标指的是您示例中的Post。解耦这一点,当你声明 Post 类时,继承自 db.Model,对于 SQLAlchemy,它就像创建一个 object Post 和 mapping 此对象的属性到专门创建的表的列。

下面有一个 Mapper 类的实例,它负责为您创建的每个模型映射(在此处了解有关映射的更多信息:Types of Mappings)。您可以简单地让这个映射器在您的模型上调用 class_mapper 或在您的模型实例上调用 object_mapper:

from sqlalchemy.orm import object_mapper, class_mapper, 
from sqlalchemy.orm.mapper import Mapper
assert object_mapper(j) is class_mapper(User)
assert type(class_mapper(User)) is Mapper

Mapper 拥有关于模型中的列和关系的所有必要信息。当调用 Post.query.with_parent(j) 时,此信息用于查找与 Post 和 User 对象相关的属性(即关系),因此在您的情况下使用 User 填充“属性”。帖子

关于python - lazy=True 在 (Flask-)SQLAlchemy 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45139722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com