【问题标题】:Accessing SQLalchemy from a class从类访问 SQLalchemy
【发布时间】:2014-02-23 23:13:17
【问题描述】:

我正在创建一个项目,我需要创建一个类实例,该实例具有连接到数据库并从中获取数据的方法(我使用 SQLite 作为后端)。 我对flask-sqlalchemy 有一些经验,但是当谈到纯SQLAlchemy 时我迷失了。 概念如下: 用户创建DataSet 的实例,并将路径作为__init__ 参数传递到数据库。如果数据库已经存在,我只想连接到它并进行查询,如果不存在,我想使用模型创建一个新的。但我不明白该怎么做。

这是DataSet 代码:

from os.path import normcase, split, join, isfile
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import errors
import trainset
import testset


class DataSet:
    def __init__(self, path_to_set, path_to_db, train_set=False, path_to_labels=None, label_dict=None,
                 custom_name=None):
        self.__path_to_set = path_to_set
        self.__label_dict = label_dict

        if custom_name is None:
            dbpath = join(path_to_db, 'train.db')
            if train_set is False:
                dbpath = join(path_to_db, 'test.db')
        else:
            dbpath = join(path_to_db, custom_name)
        if isfile(dbpath):
            self.__prepopulated = True
        else:
            self.__prepopulated = False
        self.__dbpath = dbpath

        if train_set is True and path_to_labels is None:
            raise errors.InsufficientData('labels', 'specified')
        if train_set is True and not isfile(path_to_labels):
            raise errors.InsufficientData('labels', 'found at specified path', path_to_labels)

    def prepopulate(self):
        engine = create_engine('sqlite:////' + self.__dbpath)
        self.__prepopulated = True

这是trainset 代码:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, PickleType, Integer, MetaData

Base = declarative_base()
metadata = MetaData()


class TrainSet(Base):
    __tablename__ = 'train set'
    id = Column(Integer, primary_key=True)
    real_id = Column(String(60))
    path = Column(String(120))
    labels = Column(PickleType)
    features = Column(PickleType)

这是testset 代码:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, PickleType, Integer, MetaData

Base = declarative_base()
metadata = MetaData()


class TestSet(Base):
    __tablename__ = 'test set'
    id = Column(Integer, primary_key=True)
    real_id = Column(String(60))
    path = Column(String(120))
    features = Column(PickleType)

所以,如果用户在创建DataSet 实例时传递了train_set=True,我想使用TrainSet 模型创建一个数据库,否则创建一个TestSet 数据库。我希望在 prepopulate 方法中发生这种情况,但是,我不明白该怎么做 - 文档要求这样做:Base.metadata.create_all(engine),但我不知道将这段代码放在哪里。

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    先保存参数train_set

    class DataSet:
        def __init__(self, path_to_set, path_to_db, train_set=False, path_to_labels=None, label_dict=None,
                     custom_name=None):
            self._train_set = train_set
            # ...
    

    然后,在prepopulate 中使用它来创建合适的模型:

    def prepopulate(self):
        engine = create_engine('sqlite:////' + self.__dbpath)
        if self._train_set:
            trainset.Base.create_all(engine)
        else:
            testset.Base.create_all(engine)
        self.__prepopulated = True
    

    还有一件事:不要在“私有”变量前加上双下划线。请阅读PEP 8 -- Style Guide for Python Code 以供参考。

    【讨论】:

    • 太好了,谢谢!我只需要将testset.Base.create_all(engine) 更改为testset.Base.metadata.create_all(engine)train set 也是如此),但现在一切正常。另外,由于我将编写很多查询内容的函数,将引擎存储在类实例中是个好主意吗? (而不是在每个类方法中创建)?
    • 我不会将引擎存储在任何模型类中,因为你会将错误的东西混合在一起,并且会以一种奇怪的方式耦合所有东西(model 应该什么都不知道关于连接)。相反,在类方法中只需使用object_session(self) 来获取会话(a-la transaction)并根据需要查询其他数据。
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 2016-11-12
    • 1970-01-01
    • 2019-02-23
    • 2018-07-25
    • 1970-01-01
    相关资源
    最近更新 更多