Как автоматически отразить базу данных в декларативной sqlalchemy? - PullRequest
33 голосов
/ 09 июня 2011

sqlautocode - есть проблемы с отношениями "многие ко многим"

sqlsoup - не поддерживает отношения

эликсир - это автоматическая генерация заметки

Есть ли что-то ещеЯ мог бы попробовать?

Ответы [ 3 ]

70 голосов
/ 10 июня 2011

Теоретически отражение в sqlalchemy должно работать на вас. В этом случае я использую базу данных mssql с двумя таблицами, которые имеют простое отношение «многие к одному»:

«Тесты» с полями:

  • ID
  • АСМАП
  • author_id (внешний ключ к таблице Users, поле 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)

Так что это похоже на работу с табличными отношениями. Хотя вы до сих пор не предоставили подробных сведений о том, что именно вы пытаетесь сделать.

25 голосов
/ 22 июня 2011

Ну, я прошел через это, попробовал базу данных 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:pass@Northwind', 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')
24 голосов
/ 15 июля 2013

Вы можете использовать sqlacodegen для генерации всех моделей из базы данных.Однако вам нужно позаботиться о внешнем ключе вручную.

...