我正在学习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.postsPost.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)给定的...theproperty可以是None,在这种情况下,将对该查询对象的目标映射程序执行搜索。
所以最后三个语句看起来是一样的,但我不太明白这个查询对象的目标映射器所指的是什么。本例中是Post吗,因为此查询是在Post上执行的。
发布于 2017-07-17 11:29:32
即使生成的SQL语句相同,您登记的命令也可能对应用程序产生不同的影响,例如,j.posts将缓存(回忆录,不要与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,这就像创建一个对象Post并将该对象的属性映射到专门创建的表的列。
在下面有一个Mapper类的实例,它负责您创建的每个模型的映射(在这里了解更多关于映射的信息:映射类型)。您可以简单地获得这个映射器,在您的模型上调用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 MapperMapper拥有关于模型中的列和关系的所有必要信息。调用Post.query.with_parent(j)时,此信息用于查找与Post和用户对象相关的属性(即关系),因此在您的示例中使用User.posts填充“property”。
发布于 2017-07-17 09:50:25
要查看查询,可以使用-i运行python脚本,然后单独运行每个查询,然后打印出运行的SQL代码。示例:
main.py
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'),以删除创建数据库和其他一些东西中所有不必要的输出。
https://stackoverflow.com/questions/45139722
复制相似问题