这是我的Flask-SQLAlchemy声明性代码:
from sqlalchemy.ext.associationproxy import association_proxy
from my_flask_project import db
tagging = db.Table('tagging',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id', ondelete='cascade'), primary_key=True),
db.Column('role_id', db.Integer, db.ForeignKey('role.id', ondelete='cascade'), primary_key=True)
)
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
def __init__(self, name=None):
self.name = name
@classmethod
def delete_orphans(cls):
for tag in Tag.query.outerjoin(tagging).filter(tagging.c.role_id == None):
db.session.delete(tag)
class Role(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='cascade'))
user = db.relationship('User', backref=db.backref('roles', cascade='all', lazy='dynamic'))
...
tags = db.relationship('Tag', secondary=tagging, cascade='all', backref=db.backref('roles', cascade='all'))
tag_names = association_proxy('tags', 'name')
__table_args__ = (
db.UniqueConstraint('user_id', 'check_id'),
)
基本上,它是使用Declarative进行多对多标记。从标记中删除某些条目时,我希望SQLAlchemy整理这些孤儿。正如我在文档中发现的那样,要启用此功能,我应该这样做:
class Role(db.Model):
...
tags = db.relationship('Tag', secondary=tagging, cascade='all,delete-orphan', backref=db.backref('roles', cascade='all'))
...
但是,这种设置会导致 AssertionError:此AttributeImpl未配置为跟踪父级。
我用它搜索了一下,除了SQLAlchemy的开源代码外,什么都没找到。因此,我创建了类方法Tag.delete_orphans()
(在上面的代码中),每次我认为可能会出现一些孤儿时都调用它,但这似乎不是很优雅。
有什么想法或解释为什么我的设置delete-orphan
不起作用?
好的,在这种情况下,您需要仔细查看,尽管这里有一个警告可能会成为例外,我将对此进行调查。这是您的示例的有效版本:
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base= declarative_base()
tagging = Table('tagging',Base.metadata,
Column('tag_id', Integer, ForeignKey('tag.id', ondelete='cascade'), primary_key=True),
Column('role_id', Integer, ForeignKey('role.id', ondelete='cascade'), primary_key=True)
)
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
name = Column(String(100), unique=True, nullable=False)
def __init__(self, name=None):
self.name = name
class Role(Base):
__tablename__ = 'role'
id = Column(Integer, primary_key=True)
tag_names = association_proxy('tags', 'name')
tags = relationship('Tag',
secondary=tagging,
cascade='all,delete-orphan',
backref=backref('roles', cascade='all'))
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
r1 = Role()
r1.tag_names.extend(["t1", "t2", "t3"])
s.add(r1)
s.commit()
现在开始运行:
... creates tables
/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/properties.py:918: SAWarning: On Role.tags, delete-orphan cascade is not supported on a many-to-many or many-to-one relationship when single_parent is not set. Set single_parent=True on the relationship().
self._determine_direction()
Traceback (most recent call last):
... stacktrace ...
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 349, in hasparent
assert self.trackparent, "This AttributeImpl is not configured to track parents."
AssertionError: This AttributeImpl is not configured to track parents.
因此,这是重要的部分: SAWarning:在Role.tags上,未设置single_parent时,多对多或多对一关系不支持删除孤立级联。
在relationship()上设置single_parent = True。
因此,错误是固定的,如果您这样说:
tags = relationship('Tag',
secondary=tagging,
cascade='all,delete-orphan',
single_parent=True,
backref=backref('roles', cascade='all'))
但是,您可能会发现,这并不是您真正想要的:
r1 = Role()
r2 = Role()
t1, t2 = Tag("t1"), Tag("t2")
r1.tags.extend([t1, t2])
r2.tags.append(t1)
输出:
sqlalchemy.exc.InvalidRequestError: Instance <Tag at 0x101503a10> is already associated with an instance of <class '__main__.Role'> via its Role.tags attribute, and is only allowed a single parent.
那就是您的“单亲”-“删除-孤立”功能仅适用于所谓的 生命周期
关系,其中子完全位于其单亲的范围内。因此,使用多对多的“孤立”几乎没有任何意义,它仅受支持,因为有些人确实非常想通过关联表获得此行为(无论是传统DB的东西)。
继承人的文档:
delete-
orphan级联意味着每个子对象一次只能有一个父对象,因此在大多数情况下都将其配置为一对多关系。将其设置为多对一或多对多关系比较麻烦;对于此用例,SQLAlchemy要求使用single_parent
= True函数配置Relationship(),该函数建立Python端验证,以确保该对象一次仅与一个父对象关联。
当您说“我要它清理孤儿”时,意味着什么?这意味着在这里,如果您要说r1.tags.remove(t1)
,那么您说的是“flush”。SQLAlchemy会看到“ r1.tags,t1已被删除,如果它是一个孤儿,我们需要删除!好吧,所以我们开始进行“标记”,然后
扫描整个表 对于剩余的任何条目。“一次只为每个标签天真地进行操作显然是非常低效的-
如果您在一个会话中影响了数百个标签集合,那么将有数百个这样的潜在巨大查询。这增加了相当复杂的功能,因为工作单元倾向于一次考虑一个集合,并且仍然会增加人们可能并不想要的明显的查询开销。在现实中,“删除-
孤立”系统仅在将对象B从内存中的对象A分离时才起作用-无需扫描数据库或类似的东西,它是
因此,您在此处使用“删除孤儿”所做的事情是正确的,但让我们将其粘贴到事件中,并使用更高效的查询,并一次性删除我们不需要的所有内容:
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import event
Base= declarative_base()
tagging = Table('tagging',Base.metadata,
Column('tag_id', Integer, ForeignKey('tag.id', ondelete='cascade'), primary_key=True),
Column('role_id', Integer, ForeignKey('role.id', ondelete='cascade'), primary_key=True)
)
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
name = Column(String(100), unique=True, nullable=False)
def __init__(self, name=None):
self.name = name
class Role(Base):
__tablename__ = 'role'
id = Column(Integer, primary_key=True)
tag_names = association_proxy('tags', 'name')
tags = relationship('Tag',
secondary=tagging,
backref='roles')
@event.listens_for(Session, 'after_flush')
def delete_tag_orphans(session, ctx):
session.query(Tag).\
filter(~Tag.roles.any()).\
delete(synchronize_session=False)
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
r1 = Role()
r2 = Role()
r3 = Role()
t1, t2, t3, t4 = Tag("t1"), Tag("t2"), Tag("t3"), Tag("t4")
r1.tags.extend([t1, t2])
r2.tags.extend([t2, t3])
r3.tags.extend([t4])
s.add_all([r1, r2, r3])
assert s.query(Tag).count() == 4
r2.tags.remove(t2)
assert s.query(Tag).count() == 4
r1.tags.remove(t2)
assert s.query(Tag).count() == 3
r1.tags.remove(t1)
assert s.query(Tag).count() == 2
现在每次刷新时,我们都会在末尾得到以下查询:
DELETE FROM tag WHERE NOT (EXISTS (SELECT 1
FROM tagging, role
WHERE tag.id = tagging.tag_id AND role.id = tagging.role_id))
因此,当我们可以按照简单的SQL准则删除对象时,就不需要将对象拉入内存以将其删除(通过痛苦的行编程,当数据库可以更有效地执行操作时,依靠将行拉入内存已被称为行)。)。与在计划器中往往更昂贵的“外部联接”相比,“不存在”在搜索相关行的缺失时也非常有效。
我正在尝试设置一个使用Jaeger/Prometheus的Spring应用程序。我已经通过prometheus.yaml文件成功配置了Prometheus,但我不明白如何配置Jaeger目标endpoint。我必须创建一个新的yaml文件并在其中指定配置吗?如果是,使用哪种语法?
问题内容: 我有一个使用jQuery.ajax对另一个主机执行请求的Web应用程序(现在实际上是相同的,因为我使用的是“ localhost”的不同端口)。然后服务器返回一个cookie。 Chrome的开发工具中显示的HTTP响应中的cookie值为 因此未来的有效期为4个小时。 但是,该cookie不会与后续请求一起存储和发送(已在Chrome和Firefox中进行了测试)。我首先认为它一定是
本节包括 使用声明性定义映射属性 . 关系论据的评估 此分区已移至 关系论据的后期评估 . 配置多对多关系 此分区已移至 多对多关系的延迟评估 .
本节介绍 relationship() 并深入探讨其用途。有关关系的介绍,请从 对象关系教程(1.x API) 并入 建立关系 . 基本关系模式 一对多 为一对多配置删除行为 多对一 一对一 多对多 从多对多表中删除行 关联对象 关系论据的后期评估 多对多关系的延迟评估 相邻列表关系 复合邻接表 自引用查询策略 配置自引用预加载 链接与backref的关系 backref参数 设置反向引用的层叠
有关zipkin跟踪配置的示例,请参阅zipkin沙箱设置。 返回 上一级
cmf_set_option($key, $data, $replace = false) 功能 设置系统配置,通用 参数 $key: string 配置键值,都小写 $data: array 配置值,数组 $replace: array 是否完全替换 返回 bool 是否成功