2017-02-21 38 views
1

У меня есть проект, где я хочу, чтобы изолировать инициализацию DB (SQLAlchemy) из другого модуля, поэтому я создать модульПользовательского SQLAlchemy создания двигателя в модуле

db_initializer.py:

engine = create_engine('sqlite:///db') # TODO from config file 
Session = sessionmaker(bind=engine) 
Base = declarative_base(bind=engine) 


def create_tables(): 
    Base.metadata.create_all(engine) 

Прежде всего Мне нужно поставить create_all в функцию, потому что моя модель находится в другом пакете.

model/foo.py:

from core.db_initializer import Base 

class User(Base): 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 

    def __init__(self, name: str = None): 
     self.name = name 

    def __repr__(self): 
     return "<User(id=%d, name=%s)>" % (int(self.id), str(self.name)) 

И мое главное create_tables вызова.

Есть ли другие проблемы? И теперь мне нужно создать движок с настраиваемой конфигурацией (IP, User, ...), и только основной скрипт знает конфигурацию, это возможно?

Что-то вроде

main.py:

import db_initializer as db 
import model.foo 
db.init(config) # which create the engine and create table 

Когда я что-то подобное у меня проблемы с объектом базы, которые не связываются с двигателем, который еще не создан. Любые решения?

ответ

1

Вам не нужно создавать двигатель или сеанс перед объявлением моделей. Вы можете объявить модели в модели/foo.py:

from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class User(Base): 
    __tablename__ = 'user' 

Давайте предположим, что у вас есть какое-либо приложение в myapp.py. Объявить его, поэтому он может быть инициализирован с двигателем:

from sqlalchemy.orm import Session 
import model.foo 

class MyApp: 
    def __init__(self, engine): 
     self.engine = engine 

    def get_users(self): 
     session = Session(self.engine) 
     users = session.query(model.foo.User).all() 
     session.close() 

     return users 

Создание двигателя в main.py и использовать его для инициализации models.foo.Base.metadata и других приложений, где это необходимо:

from sqlalchemy import create_engine 
import model.foo 
import myapp 

engine = create_engine('sqlite:///db') 

model.foo.Base.metadata.bind = engine 
model.foo.Base.metadata.create_all() 

app = myapp.MyApp(engine) 

UPD: Для scoped_session подход myapp.py может выглядеть следующим образом:

import model.foo 

class MyApp: 
    def __init__(self, session): 
     self.session = session 

    def get_users(self): 
     return self.session.query(model.foo.User).all() 

И main.py:

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker, scoped_session 
import model.foo 
import myapp 

engine = create_engine('sqlite:///db') 
session = scoped_session(sessionmaker(engine)) 

model.foo.Base.metadata.bind = engine 
model.foo.Base.metadata.create_all() 

app = myapp.MyApp(session) 
+0

Как вы справитесь, когда у вас будет много модели? Если я определяю Base в __init__.py и использовать его во всех подмодулях, это хорошая практика? – Timo

+0

@Timo Если у вас есть модели в нескольких файлах, вы можете объявить 'Base' в отдельной модели модуля/base.py, а затем импортировать их в model/foo.py, model/bar.py, main.py и т. Д. Вы не необходимо определить его во время инициализации, вы используете свои метаданные только при создании движка. –

+0

Спасибо! Но последний вопрос, как это сделать, если вы хотите использовать scoped_session и sessionmaker? – Timo

Смежные вопросы