简体   繁体   English

SQLAlchemy邻接列表查询

[英]SQLAlchemy Adjacency List Queries

I'm attempting to create a simple Flask application that models network devices and their membership to arbitrarily-named domains (if it's relevant, the tool will be used to define MPLS LSP meshes between the devices. I'm using sqlite for dev and production will be postgres). 我正在尝试创建一个简单的Flask应用程序,该应用程序可以对网络设备及其隶属任意命名的域的成员进行建模(如果相关,该工具将用于定义设备之间的MPLS LSP网格。我正在使用sqlite进行开发和生产)将是postgres)。 The relationships should go as follows: 关系应该如下:

  • domain to subdomain: one to many 域到子域:一对多
  • domain to device: one to many 域到设备:一对多
  • subdomain to domain: one to one 子域到域:一对一
  • device to domain: one to one 设备到域:一对一

Here is my model: 这是我的模型:

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)

How can I structure my SQLAlchemy query to start at the device itself and recurse up the tree to get to the given root Domain (with no parents) in order to generate a list of devices in each domain up the tree? 我怎样组织我的SQLAlchemy查询开始在设备本身以及递归树去,以便生成装置在每个域上树列表中的给定根域(无父母)? As an example: 举个例子:

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()

The goal here is, given switch_1 as an input, how do I get a list of other devices in its domain, plus the devices in its parent domain (and, if it applies in the real world, recurse until I reach its root domain)? 这里的目标是,在以switch_1作为输入的情况下,如何获取其域中其他设备以及其父域中的设备的列表(并且,如果适用于现实世界,则递归直到我到达其根域) ?

Traversing tree structures can be done using a recursive Common Table Expression in SQL. 遍历树结构可以使用SQL中的递归通用表表达式来完成。 Given your goal to fetch the domain of a device and its possible parent domains, and then all the devices in those domains, you could start by creating a CTE for fetching the domains: 给定您要获取设备域及其可能的父域以及这些域中所有设备的目标,可以从创建用于获取域的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))

And then just fetch the devices that are in the found domains: 然后仅获取找到的域中的设备:

db.session.query(Device).\
    join(domain_query, domain_query.c.id == Device.domain_id).\
    all()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM