SQLAlchemy不支持的类型错误及表设计问题?
又回来了,继续聊聊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)
我的问题是:
我是不是在尝试把一个对象存储到数据库字段里?
那么正确的方法是把项目信息(项目ID、名称等)复制到自己的表中,由唯一的项目ID进行引用?这样我可以让学生表中的项目ID字段只是一个整数ID,当我需要更多信息时,只需
join
这些表?其他表也是如此?如果上面的说法有道理,那么如何维护一个表中信息列与另一个表中的键索引之间的关系呢?
这是不是归结为一个数据库设计问题?
还有没有其他优雅的方法来实现这个?
如果这个问题说得很啰嗦,我表示歉意。对我来说解决这个问题非常重要,所以我尽量解释得详细一些,同时也想表明我在努力(这里的关键字可惜是“努力”)理解可能出错的地方。
1 个回答
你是不是希望SQLAlchemy能神奇地把你的对象和对象集合转换成整数值?这可不可能。SQLAlchemy可以把相关的对象存储在不同的表里,或者把它们序列化,但它没有读心术,不能知道你在想什么。所以你得明确地告诉它你的选择。
关于你的问题,答案如下:
- 是的,把对象添加到会话中,然后提交,就会把你的对象存储到数据库里。
- 是的,把相关的对象存储在不同的表中是很常见的做法。SQLAlchemy处理得很好,所以在大多数情况下你不需要明确指定连接。
- 在SQLAlchemy的教程中,有一章关于这个主题的好章节。
- 把相关的对象存储在不同的表中不会造成数据库设计上的问题。这是大多数情况下的常用做法。
- 使用不同的表是大多数情况下的最佳选择。不过,还有一种
PickleType
列类型,它使用BLOB来存储序列化的对象。