2010-04-09 4 views
1

Еще раз с некоторыми синтаксисами 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, который отображается в словаре, используя уникальный идентификатор проекта (pid) в качестве ключей. Таким образом, поскольку я перебираю каждого ученика через их rank и в набор preferences, он не является идентификатором проекта, а ссылкой на идентификатор проекта из projects.

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

Теперь это очень полезно для меня, так как я могу узнать все, что я хочу о предпочтительных проектах студента без необходимости запускать другую проверку, чтобы потянуть информацию о ид проекта. Форма вы видите в ошибке содержит информацию, объект печати передается как:

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

Мои вопросы:

  1. Я пытаюсь сохранить объект в поле базы данных, не так ли?

  2. Правильно ли будет копирование информации о проекте (идентификатор проекта, имя и т. Д.) В его собственную таблицу, на которую ссылается уникальный идентификатор проекта? Таким образом, я могу просто иметь поле id проекта для одной из таблиц учеников, просто быть целым id, и когда мне нужна дополнительная информация, просто join таблицы? Так и так далее для других столов?

  3. Если это имеет смысл, то как поддерживать связь с столбцом информации в одной таблице, которая является ключевым индексом в другой таблице?

  4. Означает ли это, что проблема с базой данных?

  5. Есть ли другие элегантные способы решения этой задачи?

Извините, если это очень длинный вопрос. Для меня очень важно решить эту проблему, поэтому я попытался объяснить как можно больше, пытаясь показать, что я пытается найти (ключевое слово здесь печально), чтобы понять, что может быть неправильным.

ответ

4

Ожидаете ли вы, что SQLAlchemy волшебным образом преобразует ваш объект и коллекцию объектов в целочисленное значение? Это невозможно. SQLAlchemy может хранить связанные объекты в отдельных таблицах или сериализован, но у него нет телепатических алгоритмов, чтобы читать ваши мысли. Поэтому вы должны четко охарактеризовать свой выбор.

Ответы на вопросы:

  1. Да, добавив к сессии, а затем совершает будет хранить объект [ы] в базу данных.
  2. Да, хранение связанных объектов в отдельной таблице - довольно распространенная идиома. SQLAlchemy обрабатывает довольно хорошо, поэтому вам не нужно явно указывать соединения в большинстве случаев.
  3. В учебнике по SQLAlchemy есть good chapter.
  4. Сохранение связанных объектов в отдельной таблице не вызывает проблем с дизайном базы данных. Это идиома используется в большинстве случаев.
  5. Использование отдельной таблицы - лучший способ для большинства случаев. Но есть также тип столбца PickleType, который использует BLOB для хранения сериализованного объекта.
+0

Я понял, что даже если в моей таблице указаны только два столбца: 'sid' и' name', я могу получить другую информацию, такую ​​как alloc_project, используя (например) 'student.allocated_project' , Просто добавление его в столбе стола приводит к хаосу. Я попытался использовать 'PickleType', но получаю сообщение об ошибке в строках' Объекты, хранящиеся в PickleType, когда mutable = True должен реализовать __eq __() для надежного сравнения. ' – PizzAzzra

+0

В некотором смысле предыдущий код фактически связывал Student и Классы проектов с использованием словаря 'projects'. Тем не менее, просто для того, чтобы держать вещи дискретными, я только что добавил в класс Student 'alloc_proj_ref', который становится внешним ключом в' projects_table' и как таковой, я могу обойтись без 'alloc_project'. Однако мне все же нужно использовать его для моего алгоритма распределения. – PizzAzzra

+0

Сообщение об ошибке для 'PickleType' верное: SQLAlchemy должно знать, изменяется ли объект и должен быть обновлен в базе данных. Поэтому вы должны предоставить метод '__eq__' - способ получить эту информацию. –

Смежные вопросы