SQLAlchemy不支持的类型错误及表设计问题?

1 投票
1 回答
3514 浏览
提问于 2025-04-15 21:25

又回来了,继续聊聊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时,它实际上是指向Project类,这个类映射到一个字典,使用唯一的项目ID(pid)作为键。因此,当我通过每个学生的rank遍历到preferences集合时,它add的不是项目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. 还有没有其他优雅的方法来实现这个?

如果这个问题说得很啰嗦,我表示歉意。对我来说解决这个问题非常重要,所以我尽量解释得详细一些,同时也想表明我在努力(这里的关键字可惜是“努力”)理解可能出错的地方。

1 个回答

4

你是不是希望SQLAlchemy能神奇地把你的对象和对象集合转换成整数值?这可不可能。SQLAlchemy可以把相关的对象存储在不同的表里,或者把它们序列化,但它没有读心术,不能知道你在想什么。所以你得明确地告诉它你的选择。

关于你的问题,答案如下:

  1. 是的,把对象添加到会话中,然后提交,就会把你的对象存储到数据库里。
  2. 是的,把相关的对象存储在不同的表中是很常见的做法。SQLAlchemy处理得很好,所以在大多数情况下你不需要明确指定连接。
  3. 在SQLAlchemy的教程中,有一章关于这个主题的好章节
  4. 把相关的对象存储在不同的表中不会造成数据库设计上的问题。这是大多数情况下的常用做法。
  5. 使用不同的表是大多数情况下的最佳选择。不过,还有一种PickleType列类型,它使用BLOB来存储序列化的对象。

撰写回答