【问题标题】:SQLAlchemy unsupported type error - and table design issues?SQLAlchemy 不支持的类型错误 - 和表设计问题?
【发布时间】:2010-04-10 19:19:26
【问题描述】:

再次返回一些 SQLAlchemy 恶作剧。

让我一步一步来。

我的桌子现在是这样设置的:

engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()
students_table = Table('studs', metadata,
    Column('sid', Integer, primary_key=True),
    Column('name', String),
    Column('preferences', Integer),
    Column('allocated_rank', Integer),
    Column('allocated_project', Integer)
)
metadata.create_all(engine)
mapper(Student, students_table)  

相当简单,而且在大多数情况下,只要我避免出现以下错误情况,我就可以查询几乎任何我想要的信息。

它所映射的类是:

class Student(object):
    def __init__(self, sid, name):
        self.sid = sid
        self.name = name
        self.preferences = collections.defaultdict(set)
        self.allocated_project = None
        self.allocated_rank = 0

def __repr__(self):
    return str(self)

def __str__(self):
    return "%s %s" %(self.sid, self.name)  

解释:preferences 基本上是学生希望分配的所有项目的集合。当分配算法启动时,学生的allocated_project 会从这个偏好集中出现。

现在如果我尝试这样做:

for student in students.itervalues():
    session.add(student)

session.commit()

它会引发两个错误,一个是allocated_project 列(见下文),另一个是preferences 列的类似错误:

sqlalchemy.exc.InterfaceError: (InterfaceError) Error binding parameter 4 
- probably unsupported type. u'INSERT INTO studs (sid, name, allocated_rank, 
allocated_project) VALUES (?, ?, ?, ?, ?, ?, ?)' 
[1101, 'Muffett,M.', 1, 888 Human-spider relationships (Supervisor id: 123)]  

如果我回到我的代码中,我会发现,当我从给定的文本文件中复制 preferences 时,它实际上是指使用唯一项目 ID 映射到字典的 Project 类(pid) 作为键。因此,当我通过每个学生的rankpreferences 集合遍历每个学生时,它adds 不是项目ID,而是来自projects 字典中对项目ID 的引用。

students[sid].preferences[int(rank)].add(projects[int(pid)])

现在这对我来说非常有用,因为我可以找到所有我想要的关于学生首选项目的信息,而无需再次检查以获取有关项目 ID 的信息。您在错误中看到的表单将对象打印信息传递为:

return "%s %s (Supervisor id: %s)" %(self.proj_id, self.proj_name, self.proj_sup)

我的问题是:

  1. 我正在尝试将对象存储在数据库字段中,不是吗?

  2. 那么正确的方法是将项目信息(项目 ID、名称等)复制到其自己的表中,由唯一的项目 ID 引用吗?这样我就可以让其中一个学生表的项目 id 字段只是一个整数 id,当我需要更多信息时,只需 join 表?其他表的等等?

  3. 如果上面说得通,那么如何维护与一个表中作为另一表键索引的信息列的关系?

  4. 这是否归结为数据库设计问题?

  5. 还有其他优雅的方法可以实现这一点吗?

如果这是一个冗长的问题,我们深表歉意。解决这个问题对我来说非常重要,所以我试图尽可能多地解释,同时试图表明我正在尝试(可悲的是这里的关键词)来理解可能发生的事情错了。

【问题讨论】:

    标签: python database-design sqlalchemy


    【解决方案1】:

    您是否期望 SQLAlchemy 神奇地将您的对象和对象集合转换为整数值?不可能。 SQLAlchemy 可以将相关对象存储在单独的表中或序列化,但它没有心灵感应算法来读懂你的想法。所以你必须明确地描述你的选择。

    回答您的问题:

    1. 是的,添加到会话然后提交会将您的对象存储到数据库中。
    2. 是的,将相关对象存储在单独的表中是很常见的习惯用法。 SQLAlchemy 处理得非常好,因此在大多数情况下您不需要显式指定连接。
    3. 在 SQLAlchemy 教程中有 good chapter 关于这个主题。
    4. 将相关对象存储在单独的表中不会导致数据库设计问题。这是大多数情况下使用的成语。
    5. 在大多数情况下,使用单独的表格是最好的方法。但也有一个PickleType 列类型,它使用 BLOB 来存储序列化对象。

    【讨论】:

    • 我意识到的一件事是,即使我的表只有两列,例如sidname,我仍然可以通过使用(例如)@987654325 获取其他信息,例如分配项目@。只是将其添加为表格列会造成严重破坏。我尝试使用PickleType,但出现Objects stored with PickleType when mutable=True must implement __eq__() for reliable comparison. 的错误
    • 在某种程度上,前面的代码实际上是使用 projects 字典链接 Student 和 Project 类。然而,为了保持离散,我刚刚在我的学生类中添加了一个allocated_proj_ref,它成为projects_table 的外键,因此,我可以不用allocated_project。但是我仍然需要将它用于我的分配算法。
    • PickleType 的错误信息是正确的:SQLAlchemy 需要知道对象是否被更改并且应该在数据库中更新。所以你必须提供__eq__ 方法——一种获取这些信息的方法。
    • 很抱歉问这个问题,但你能解释一下我应该如何添加这个吗?我尝试使用PickleType(comparator=operator.eq),但随后又引发了另一个错误,我相信询问“比较器”。
    • def __eq__(...) 在您要存储的对象类中有什么问题?
    猜你喜欢
    • 2015-03-26
    • 2014-05-23
    • 1970-01-01
    • 2015-08-21
    • 2021-06-05
    • 2017-05-27
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    相关资源
    最近更新 更多