使用外键映射通过Python和SQLAlchemy从其他表获取数据

4 投票
1 回答
5857 浏览
提问于 2025-04-15 23:13

嗯,标题比我想的要难写。

简单来说,我有一些简单的类,它们和数据库表对应,使用的是SQLAlchemy。我知道这些类缺少一些东西,但那些并不是解决问题的关键。

class Customer(object):
    def __init__(self, uid, name, email):
        self.uid = uid
        self.name = name
        self.email = email

    def __repr__(self):
        return str(self)

    def __str__(self):
        return "Cust: %s, Name: %s (Email: %s)" %(self.uid, self.name, self.email)  

上面的代码基本上是一个简单的客户类,包含了一个ID、名字和电子邮件地址。

class Order(object):
    def __init__(self, item_id, item_name, customer):
        self.item_id = item_id
        self.item_name = item_name
        self.customer = None

    def __repr__(self):
        return str(self)

    def __str__(self):
        return "Item ID %s: %s, has been ordered by customer no. %s" %(self.item_id, self.item_name, self.customer)  

这是一个Orders类,它只存储订单信息:一个ID、一个名字和一个指向客户的引用。它初始化为None,表示这个订单还没有关联的客户。后面的代码会给这个订单分配一个客户。

接下来的代码将这些类映射到相应的数据库表。

# SQLAlchemy database transmutation
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()

customers_table = Table('customers', metadata,
    Column('uid', Integer, primary_key=True),
    Column('name', String),
    Column('email', String)
)


orders_table = Table('orders', metadata,
    Column('item_id', Integer, primary_key=True),
    Column('item_name', String),
    Column('customer', Integer, ForeignKey('customers.uid'))
)

metadata.create_all(engine)
mapper(Customer, customers_table)
mapper(Order, orders_table)  

现在如果我做一些这样的操作:

for order in session.query(Order):
    print order  

我可以得到一个这样的订单列表:

Item ID 1001: MX4000 Laser Mouse, has been ordered by customer no. 12  

我想要做的是找出客户12的名字和电子邮件地址(这就是我为什么在客户表中使用外键的原因)。我该怎么做呢?

根据我的评论更新

我知道这看起来有点没用,但只是为了了解一下:我需要做什么才能保持这种单向关系?

另外,如果我还有一个指向另一个表的外键,我该如何更新映射?

1 个回答

5

首先,如果你在创建订单的时候传入了客户信息,那就至少要用上这个客户信息。我建议你使用一个默认值,但在创建时仍然允许给客户赋值,像下面这样:

class Order(object):
    def __init__(self, item_id, item_name, customer=None):
        self.item_id = item_id
        self.item_name = item_name
        self.customer = customer # self.customer = None
    #...

为了让你们之间的关系正常工作,你需要初始化对象之间的关系,仅仅有外键是不够的。我建议你把代码改成下面这样(摘录部分):

orders_table = Table('orders', metadata,
    Column('item_id', Integer, primary_key=True),
    Column('item_name', String),
    Column('customer_id', Integer, ForeignKey('customers.uid')) # changed
)

# for bi-directional relationship use:
mapper(Customer, customers_table, properties={
    'orders': relationship(Orders, backref='customer')
})
mapper(Orders, orders_table)
# for uni-directional relationship use:
mapper(Customer, customers_table)
mapper(Orders, orders_table, properties={
    'customer': relationship(Customer)
})
#...

这样你就可以从订单找到客户,再反过来找到订单了:

print mycustomer.orders # in case of bi-directional
print order.customer

撰写回答