Sqlalchemy 用整数替换文本

Sqalchemy substituting text with integers

我正在使用 Sqlalchemy 设计一个数据库来记录实验室测量值。每个测试结果我都有一个table。我想将测试结果和名称标签存储在同一行中。每当我 运行 相同的测试时,名称标签可以出现多次。因此,我不想多次存储实际标签,而是想用一个整数替换每个标签。该整数将是另一个仅存储标签的 table 的键。

数据库table定义如下:

from sqlalchemy import Column, Integer, String, Float ,
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class TestResults(Base):

    __tablename__ = "test_results"


    id = Column(Integer, primary_key=True)
    test_name = Column(Integer)  # id value in TestNames table
    timestamp = Column(Integer)
    test_value = Column(Float)


class TestNames(Base):
    """
    Lookup table for test_name column in TestResults

    """
    __tablename__ = 'test_names'

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

理想情况下,我希望能够通过将 test_name 作为字符串输入数据到 TestResults table 中,例如

results = TestResults()
results.test_name = 'my_test'
results.test_value = 10.1

为了做到这一点,我想我需要一个中间函数来检查我输入 results.test_name 的字符串是否已经存在于 TestNames table 中,如果存在,那么 'real' results.test_name 填充了现有名称的 ID 号。如果该名称不存在,则将其添加到 TestNames,并将新名称的 ID 填充到 results.test_name。这样做的功能是这样的:

def test_name_creator(session,name):
    """
    Input
    -------
    session : sqlalchemy session object

    name : str
        New test name


    Output
    --------
    id : int
        id of test name

    """


    # Check if name already exists
    name_query = session.query(TestNames).filter(TestNames.name==name).all()
    if name_query!=[]:
        name_id = name_query[0].id
        return name_id

    # name does not exist, add to TestNames() table
    new_test_name = TestNames()
    new_test_name.name = name
    session.add(new_test_name)
    session.commit()
    return new_test_name.id

我想不通的是如何用上面的函数截取results.test_name='my_test'的设置,从而让returned id实际填充到results.test_name。我认为这是 association_proxy + creator 函数的工作,但我见过的所有示例 return Sqlalchemy declarative_base() class 对象,而不是简单的整数。

而不是 test_name_creator return ID,return 实例本身,像这样:

def test_name_creator(session, name):
    inst = session.query(TestNames).filter(TestNames.name == name).first()
    if inst is None:
        # Create new TestNames() instance and add to database
        inst = TestNames(name=name) 
        session.add(inst)
    return inst

然后,设置一个关系,以便 SQLAlchemy 找出放置 ID 的位置:

class TestResults(Base):
    ...
    test_name_id = Column(Integer, ForeignKey(TestNames.id))
    test_name = relationship(TestNames)

你这样设置名称:

results = TestResults(test_name=test_name_creator(session, "my_test"), value=10.1)

如果您想保留 test_name 的使用模式作为您可以分配给但在 TestNames 中创建行的 string,您可以使用 association proxies combined with the UniqueObject食谱。