mko*_*tee 1 python postgresql sqlalchemy
我在postgresql中有两个表,一个名为ip_address,另一个名为network.
该ip_address表有两列:
id 是一个 INTEGERv4address 是一个 INET该network表有两列:
id 是一个 INTEGERv4representation 是一个 CIDR我希望能够选择ip_address并急切加载ip_addresses network(s),而无需id在表之间定义基于外键的关系.这些id列由与其他表无关的其他关系使用.
完成此任务的SQL是:
select * from ip_address join network on ip_address.v4address << network.v4representation;
Run Code Online (Sandbox Code Playgroud)
在postgresql中,<<运算符可用于比较a INET和a CIDR.它将匹配INET包含在其中的行CIDR.
我可以property在我的IPAddress模型上定义一个可以完成此任务的模型:
@property
def networks(self):
query = session.query(Network)
query = query.filter("v4representation >> :v4addr").params(v4addr=self.v4address)
return query.all()
Run Code Online (Sandbox Code Playgroud)
这有效,但是当我真正尝试property在应用程序中使用它时,我遇到了典型的"N + 1"查询问题.我想以这样的方式定义它,以便能够急于加载IP地址网络.
我试图将其定义为relationship使用primaryjoin,但无法弄清楚需要什么.我试过这个:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address << Network.v4representation',
viewonly=True)
Run Code Online (Sandbox Code Playgroud)
但是sqlalchemy不知道如何处理<<运营商,所以我改用了这个:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address.op("<<")(Network.v4representation)',
viewonly=True)
Run Code Online (Sandbox Code Playgroud)
但sqlalchemy抛出ArgumentError:
ArgumentError: Could not locate any relevant foreign key columns for primary join condition 'public.ip_address.v4address << public.network.v4representation' on relationship IPAddress.networks. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation.
Run Code Online (Sandbox Code Playgroud)
我试着定义的几种组合foreign_key为relationship:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address.op("<<")(Network.v4representation)',
foreign_keys='[Network.v4representation]',
viewonly=True)
Run Code Online (Sandbox Code Playgroud)
但sqlalchemy抛出ArgumentErrors:ArgumentError:关系IPAddress.networks无法根据连接条件和remote_side参数确定任何明确的本地/远程列对.考虑使用remote()注释来准确标记关系远程端的连接条件的那些元素.
既不指定IPAddress.v4address或Network.v4representation作为remote_side改变异常.
没有尝试primaryjoin用foreign/ 注释条件remote也有帮助.
回到我原来的意图,我希望能够执行一个查询,它将返回IP地址并急切加载他们的网络(以及可能来自网络其他关系的数据,因为这是我的完整模式的简化).
有没有人有什么建议?
提前致谢.
这里缺少的部分是自定义运算符在关系框架内不起作用.为了帮助解决这个问题,我为SQLAlchemy 0.9.2添加了一个新功能,即"is_comparison"标志,这里有一个例子,在连接条件中使用自定义运算符.
这是一个使用较少公共API完成相同结果的版本,它也可以在0.8中使用:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import INET, CIDR
Base = declarative_base()
# workaround before 0.9.2
from sqlalchemy.sql import operators
is_contained_by = operators.custom_op("<<")
operators._comparison.add(is_contained_by)
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin=lambda: is_contained_by(
IPA.v4address,
(foreign(Network.v4representation))
),
viewonly=True
)
class Network(Base):
__tablename__ = 'network'
id = Column(Integer, primary_key=True)
v4representation = Column(CIDR)
print Session().query(IPA).join(IPA.network)
Run Code Online (Sandbox Code Playgroud)
在0.9.2及更高版本中,它可以完成为:
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin="IPA.v4address.op('<<', is_comparison=True)"
"(foreign(Network.v4representation))",
viewonly=True
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1569 次 |
| 最近记录: |