2011-06-09 51 views
31

sqlautocode - 與許多一對多的關係如何自動將數據庫反映到sqlalchemy聲明?

sqlsoup問題 - 不支持關係

靈藥 - 這注自動生成

有沒有別的東西,我可以嘗試?

+1

你究竟想要做什麼?如果我理解你,你想從數據庫表中創建尚未由sqlalchemy模型定義的聲明引用?我不確定你可以到達聲明點,但是你可以反映表的屬性(我相信這包括[外鍵](http://www.sqlalchemy.org/docs/05/metadata.html#reflecting )如 – Raceyman 2011-06-09 13:04:13

+1

正如[本答案](http://stackoverflow.com/a/14403228/3079302)中指出的那樣,SQLAlchemy具有[Automap擴展名](http://docs.sqlalchemy.org/en/latest /orm/extensions/automap.html?highlight=automap#module-sqlalchemy.ext.automap)從版本0.9.1開始。從文檔:定義對'sqlalchemy.ext.declarative'系統的擴展,該系統自動從數據庫模式生成映射類和關係,但通常不一定反映出來。 – iled 2016-01-20 16:36:09

回答

21

好吧,我經歷了這個,在Northwind數據庫上嘗試過,它看起來很有前途。雖然,我必須添加關係字段才能跟蹤數據庫關係。

讓我們考慮一下,我不知道在啓動應用程序時表之間的關係,所以我需要的是一種自動生成的方法。

import unittest 

from sqlalchemy import * 
from sqlalchemy.orm import create_session 
from sqlalchemy.ext.declarative import declarative_base 
from datetime import datetime 
from sqlalchemy.orm import contains_eager, joinedload 
from sqlalchemy.orm import relationship 

#Create and engine and get the metadata 
Base = declarative_base() 
engine = create_engine('mssql://user:[email protected]', echo=True) 
metadata = MetaData(bind=engine) 


#Reflect each database table we need to use, using metadata 
class Customer(Base): 
    __table__ = Table('Customers', metadata, autoload=True) 
    orders = relationship("Order", backref="customer") 

class Shipper(Base): 
    __table__ = Table('Shippers', metadata, autoload=True) 
    orders = relationship("Order", backref="shipper") 

class Employee(Base): 
    __table__ = Table('Employees', metadata, autoload=True) 
# orders = relationship("Order", backref="employee") 
    territories = relationship('Territory', secondary=Table('Employeeterritories', metadata, autoload=True)) 

class Territory(Base): 
    __table__ = Table('Territories', metadata, autoload=True) 
    region = relationship('Region', backref='territories') 

class Region(Base): 
    __table__ = Table('Region', metadata, autoload=True) 


class Order(Base): 
    __table__ = Table('Orders', metadata, autoload=True) 
    products = relationship('Product', secondary=Table('Order Details', metadata, autoload=True)) 
    employee = relationship('Employee', backref='orders') 

class Product(Base): 
    __table__ = Table('Products', metadata, autoload=True) 
    supplier = relationship('Supplier', backref='products') 
    category = relationship('Category', backref='products') 

class Supplier(Base): 
    __table__ = Table('Suppliers', metadata, autoload=True) 

class Category(Base): 
    __table__ = Table('Categories', metadata, autoload=True) 


class Test(unittest.TestCase): 

    def setUp(self): 
     #Create a session to use the tables  
     self.session = create_session(bind=engine)   

    def tearDown(self): 
     self.session.close() 

    def test_withJoins(self): 
     q = self.session.query(Customer) 
     q = q.join(Order) 
     q = q.join(Shipper) 
     q = q.filter(Customer.CustomerID =='ALFKI') 
     q = q.filter(Order.OrderID=='10643') 
     q = q.filter(Shipper.ShipperID=='1') 
     q = q.options(contains_eager(Customer.orders, Order.shipper)) 
     res = q.all() 
     cus = res[0] 
     ord = cus.orders[0] 
     shi = ord.shipper 
     self.assertEqual(shi.Phone, '(503) 555-9831') 
66

在理論上sqlalchemy的反思應該爲你工作。在這種情況下,我使用與具有簡單的多到一個關係的兩個表的MSSQL數據庫:

「測試」包含字段:

  • ID
  • 測試名
  • AUTHOR_ID(外鍵的用戶表,Users.id場)

「用戶」 與字段:

  • ID
  • 全稱

所以下面應該反映數據庫:

from sqlalchemy import * 
from sqlalchemy.orm import create_session 
from sqlalchemy.ext.declarative import declarative_base 

#Create and engine and get the metadata 
Base = declarative_base() 
engine = create_engine('put your database connect string here') 
metadata = MetaData(bind=engine) 

#Reflect each database table we need to use, using metadata 
class Tests(Base): 
    __table__ = Table('Tests', metadata, autoload=True) 

class Users(Base): 
    __table__ = Table('Users', metadata, autoload=True) 

#Create a session to use the tables  
session = create_session(bind=engine) 

#Here I will just query some data using my foreign key relation, as you would 
#normally do if you had created a declarative data mode. 
#Note that not all test records have an author so I need to accomodate for Null records 
testlist = session.query(Tests).all()  

for test in testlist: 
    testauthor = session.query(Users).filter_by(id=test.author_id).first() 
    if not testauthor: 
     print "Test Name: {}, No author recorded".format(test.testname) 
    else: 
     print "Test Name: {}, Test Author: {}".format(test.testname, testauthor.fullname) 

因此,這似乎與臺關係的工作。雖然你還沒有給出你準備做什麼的很多細節。

+2

這個例子沒有顯示在對象層次上表間關係的使用,對吧?換句話說,author_id是外鍵的事實不足以讓SQLAlchemy自動將'test.fullname'設爲正確的'testauthor.fullname',否? – EOL 2013-01-19 14:21:42

+0

除了python + SQLAlchemy之外,還有其他編程語言中是否有這樣的反射類型?這真棒! – maxm 2014-04-03 17:50:18

+1

定義MetaData不是必需的。創建Base還創建了可以通過'Base.metadata'訪問的MetaData實例。 – rgtk 2015-06-30 21:18:12

23

您可以使用sqlacodegen從數據庫中生成所有模型。但是,您需要手動處理外鍵。

+0

這對我有幫助。謝謝! – shaffooo 2017-12-12 23:00:36

相關問題