2010-04-09 62 views
1

再回来一些SQLAlchemy shenanigans。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)作为键。因此,当我通过rankpreferences组遍历每个学生时,其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. 是否有任何其他优雅的方式来完成此?

道歉,如果这是一个非常冗长的问题。解决这个问题对我来说非常重要,因此我试图尽可能解释,同时试图证明我是尝试(关键词在这里可悲),以了解可能出现的问题。

回答

4

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

问题的答案:

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

我已经意识到的一件事是,即使我的表只有两列表示'sid'和'name',我仍然可以通过使用(例如)'student.allocated_project'来获得诸如allocated_project之类的其他信息。只是将它添加为表格列会造成严重破坏。 我试着用'PickleType',但沿着'存储与PickleType时可变=真必须实现__eq __()用于可靠comparison.' – PizzAzzra 2010-04-10 21:56:01

+0

从某种意义上说,以前的代码实际上是链接Student对象的线条得到一个错误,使用'projects'字典的项目类。但是,为了保持事物的离散性,我刚刚在我的Student类中添加了一个'allocated_proj_ref',它成为'projects_table'中的一个外键,因此,我可以不使用'allocated_project'。不过,我仍然需要将它用于我的分配算法。 – PizzAzzra 2010-04-10 21:56:37

+0

PickleType的错误消息是正确的:SQLAlchemy需要知道对象是否已更改,并且应该在数据库中进行更新。所以你必须提供'__eq__'方法 - 一种获取这些信息的方法。 – 2010-04-12 03:47:08

相关问题