首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >lazy=True in (烧瓶-)SQLAlchemy

lazy=True in (烧瓶-)SQLAlchemy
EN

Stack Overflow用户
提问于 2017-07-17 08:51:05
回答 2查看 4.5K关注 0票数 2

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

例如

代码语言:javascript
运行
复制
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文档说:

with_parent(instance, property=None, from_entity=None) 给定的...the property可以是None,在这种情况下,将对该查询对象的目标映射程序执行搜索。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-17 11:29:32

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

如果从查询中删除.all(),只需打印它们:

代码语言:javascript
运行
复制
query = Post.query.filter_by(author=j)
print(query)

这将导致:

代码语言:javascript
运行
复制
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,它将返回如下内容:

代码语言:javascript
运行
复制
> print(j.posts)
> [Post(...), Post(..)]

尽管如此,您仍然可以使用内置sqlalchemy记录器看到所有无声发出的查询。请参阅下列代码:

代码语言:javascript
运行
复制
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,这就像创建一个对象Post并将该对象的属性映射到专门创建的表的列。

在下面有一个Mapper类的实例,它负责您创建的每个模型的映射(在这里了解更多关于映射的信息:映射类型)。您可以简单地获得这个映射器,在您的模型上调用class_mapper,或者在模型的实例上调用object_mapper

代码语言:javascript
运行
复制
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.posts填充“property”。

票数 5
EN

Stack Overflow用户

发布于 2017-07-17 09:50:25

要查看查询,可以使用-i运行python脚本,然后单独运行每个查询,然后打印出运行的SQL代码。示例:

main.py

代码语言:javascript
运行
复制
import sqlalchemy
from sqlalchemy import create_engine, Column, Integer, String, Sequence
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import os

engine = create_engine('sqlite:///:memory:', echo=True)

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
    name = Column(String(50))
    fullname = Column(String(50))
    password = Column(String(12))

    def __repr__(self):
        return "< User(name={}, fullname={}, password={} )>".format(self.name, self.fullname, self.password)

Base.metadata.create_all(engine)

ed_user= User(name='ed', fullname='Ed Jones', password='edpassword')
Session = sessionmaker(bind=engine, autoflush=False)
session = Session()
session.add(ed_user)
session.add_all([
    User(name='wendy', fullname='Wendy Williams', password='foobar'),
    User(name='mary', fullname='Mary Contraty', password='xxg527'),
    User(name='fred', fullname='Fred Flinstone', password='blah')
])
session.commit()
os.system('clear')

现在使用python -i main.py运行它,输入:session.query(User).filter_by(name='ed').first(),您将看到生成的SQL。经过正在运行所有的测试,我得出结论,它们都是完全相同的。使用此方法,您可以测试任何查询,并查看是否有任何差异。

附注:我添加了os.system('clear'),以删除创建数据库和其他一些东西中所有不必要的输出。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45139722

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档