我尝试创建一个简单的Flask应用程序,该应用程序将网络设备及其成员资格建模为任意命名的域(如果相关,则该工具将用于定义设备之间的MPLS LSP网格。我使用sqlite开发和生产将是postgres)。关系应如下:
这是我的模特:
class Device(db.Model):
__tablename__ = 'device'
id = db.Column(db.Integer, primary_key=True)
hostname = db.Column(db.String(255), unique=True)
mgmt_ip = db.Column(db.String(255), unique=True)
snmp_comm = db.Column(db.String(255))
domain_id = db.Column(db.Integer, db.ForeignKey('domain.id'))
def __repr__(self):
return '<Hostname %r>' % (self.hostname)
class Domain(db.Model):
__tablename__ = 'domain'
id = db.Column(db.Integer, primary_key=True)
parent_id = db.Column(db.Integer, db.ForeignKey('domain.id'))
name = db.Column(db.String(255), unique=True)
children = db.relationship("Domain")
devices = db.relationship("Device")
def __repr__(self):
return '<Domain %r>' % (self.name)
如何构建我的SQLAlchemy查询以启动设备本身并递归 up 树以获取给定的根域(没有父项)以生成每个设备的列表域上树?举个例子:
from app import db
from app.models import Device, Domain
db.create_all()
d1 = Domain(name='mandatory')
db.session.add(d1)
db.session.commit()
d2 = Domain(name='metro_A', parent_id=1)
db.session.add(d2)
db.session.commit()
d3 = Domain(name='metro_B', parent_id=1)
db.session.add(d3)
db.session.commit()
dev1 = Device(hostname='switch_1', mgmt_ip='1.1.1.1', snmp_comm='public', domain_id=1)
dev2 = Device(hostname='switch_2', mgmt_ip='2.2.2.2', snmp_comm='public', domain_id=1)
dev3 = Device(hostname='switch_3', mgmt_ip='3.3.3.3', snmp_comm='public', domain_id=2)
dev4 = Device(hostname='switch_4', mgmt_ip='4.4.4.4', snmp_comm='public', domain_id=2)
dev5 = Device(hostname='switch_5', mgmt_ip='5.5.5.5', snmp_comm='public', domain_id=3)
dev6 = Device(hostname='switch_6', mgmt_ip='6.6.6.6', snmp_comm='public', domain_id=3)
db.session.add_all([dev1, dev2, dev3, dev4, dev5, dev6])
db.session.commit()
此处的目标是,在switch_1
作为输入的情况下,如何获取其域中的其他设备列表, plus 其父域中的设备(如果是适用于现实世界,递归,直到我到达其根域)?
答案 0 :(得分:-1)
可以使用SQL中的递归公用表表达式来遍历树结构。鉴于您的目标是获取设备的域及其可能的父域,然后是这些域中的所有设备,您可以首先创建CTE来获取域:
domain_alias = db.aliased(Domain)
# Domain of switch_1 has no parents, so for demonstration switch_6
# is a better target.
initial = db.session.query(Domain.id, Domain.parent_id).\
join(Device).\
filter_by(hostname='switch_6').\
cte(recursive=True)
child = db.aliased(initial)
domain_query = initial.union(
db.session.query(domain_alias.id, domain_alias.parent_id).
join(child, child.c.parent_id == domain_alias.id))
然后只需获取找到的域中的设备:
db.session.query(Device).\
join(domain_query, domain_query.c.id == Device.domain_id).\
all()