joh*_*s85 11 python sqlalchemy declarative relational-database python-import
我正在设计一个小的GUI应用程序来包装一个sqlite DB(简单的CRUD操作).我已经创建了三个SQLAlchemy的模型(m_person,m_card.py,m_loan.py,全部在/models文件夹中)和以前曾在每一个顶部以下代码:
from sqlalchemy import Table, Column, create_engine
from sqlalchemy import Integer, ForeignKey, String, Unicode
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import backref, relation
engine = create_engine("sqlite:///devdata.db", echo=True)
declarative_base = declarative_base(engine)
metadata = declarative_base.metadata
Run Code Online (Sandbox Code Playgroud)
这感觉有点不对(干)所以有人建议我将所有这些东西移到模块级别(进入models/__init__.py).
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Table, Column, Boolean, Unicode
from settings import setup
engine = create_engine('sqlite:///' + setup.get_db_path(), echo=False)
declarative_base = declarative_base(engine)
metadata = declarative_base.metadata
session = sessionmaker()
session = session()
Run Code Online (Sandbox Code Playgroud)
..并declarative_base像这样导入:
from sqlalchemy import Table, Column, Unicode
from models import declarative_base
class Person(declarative_base):
"""
Person model
"""
__tablename__ = "people"
id = Column(Unicode(50), primary_key=True)
fname = Column(Unicode(50))
sname = Column(Unicode(50))
Run Code Online (Sandbox Code Playgroud)
但是我有很多反馈,因为像这样的模块导入执行代码是不好的?我正在寻找一个明确的答案正确的方法来做它似乎通过尝试删除代码重复我已经介绍了一些其他不良做法.任何反馈都非常有用.
(以下是完整性的get_db_path()方法,settings/setup.py因为它在上面的models/__init__.py代码中被调用.)
def get_db_path():
import sys
from os import makedirs
from os.path import join, dirname, exists
from constants import DB_FILE, DB_FOLDER
if len(sys.argv) > 1:
db_path = sys.argv[1]
else:
#Check if application is running from exe or .py and adjust db path accordingly
if getattr(sys, 'frozen', False):
application_path = dirname(sys.executable)
db_path = join(application_path, DB_FOLDER, DB_FILE)
elif __file__:
application_path = dirname(__file__)
db_path = join(application_path, '..', DB_FOLDER, DB_FILE)
#Check db path exists and create it if not
def ensure_directory(db_path):
dir = dirname(db_path)
if not exists(dir):
makedirs(dir)
ensure_directory(db_path)
return db_path
Run Code Online (Sandbox Code Playgroud)
一些流行的框架(Twisted是一个例子)在导入时执行大量的初始化逻辑.能够动态构建模块内容的好处确实是有代价的,其中之一就是IDE无法始终决定模块中的"内部".
在您的特定情况下,您可能需要重构,以便在导入时提供特定引擎但稍后提供.您可以declarative_base在导入时创建元数据和类.然后在开始时,在定义了所有类之后,调用create_engine并将结果绑定到您的sqlalchemy.orm.sessionmaker.但如果您的需求很简单,您甚至可能不需要那么远.
一般来说,我会说这不是Java或C.除了定义函数,类和常量之外,没有理由担心在模块级别做事情.无论如何,应用程序一个接一个地开始创建您的类.如果它简化了您的实现,那么我认为可以对类(在同一模块中)进行一些小修补,或者创建一个或两个全局查找表.
我绝对会避免的是模块中的任何代码导致导入的顺序对用户很重要(除了简单地提供逻辑的常规方式),或者修改模块外部代码的行为.然后你的模块变成黑魔法,这在Perl世界(ala use strict;)中被接受,但我发现它不是"pythonic".
例如,如果您的模块修改了sys.stdout导入时的属性,我认为应该将行为转移到用户可以调用或不调用的函数中.