Найти - Пользователи
Полная версия: [sqlalchemy] - удаление объектов
Начало » Базы данных » [sqlalchemy] - удаление объектов
1 2 3
demas
Подскажите, пожалуйста, почему вот такой код работает:

session = self.engine.createSession()
for each_product in session.query(Product):
print 'deleted %s' % each_product.name
session.delete(each_product)
session.commit()
А вот такой уже нет:

session = self.engine.createSession()
for each_product in session.query(Product):
print 'deleted %s' % each_product.name
new_product = Product(each_product.name, each_product.category, each_product.fat, each_product.protein, each_product.carbo)
session.delete(new_product)
session.commit()
То есть, насколько я понял, удалить можно только объект, полученный непосредственно от sqlAlchemy, а если я создаю его точную (deep) копию, то она уже не удаляется:

File “sqlalchemy_test.py”, line 54, in deleteProduct
session.delete(new_product)
File “/var/lib/python-support/python2.5/sqlalchemy/orm/session.py”, line 954, in delete
self._delete_impl(instance)
File “/var/lib/python-support/python2.5/sqlalchemy/orm/session.py”, line 1121, in _delete_impl
raise exceptions.InvalidRequestError(“Instance ‘%s’ is not persisted” % mapperutil.instance_str(instance))
sqlalchemy.exceptions.InvalidRequestError: Instance ‘Product@0x9f6a22c’ is not persisted

Вопрос собственно прав ли я и какой в этом глубокий смысл?
Ну и как правильно выходить из этой ситуации? У меня есть gui - treeview, где в каждой строке у меня хранится информация достаточная для того, чтобы полностью создать объект для удаления (через new). Получается, что я должен не создавать объект сам, а заново вычитывать его из базы данных с помощью sqlAlchemy?
j2a
Нееееее. Читай http://www.sqlalchemy.org/docs/05/session.html#unitofwork_using_states – у тебя новый объект в состоянии pending.
demas
Хм…
Почему новый? Он создан еще вчера и с тех пор я закрывал запущенную программу.

Pending - when you add() a transient instance, it becomes pending. It still wasn't actually flushed to the database yet, but it will be when the next flush occurs.
Ну как он может быть не сброшен на диск, если после add я даже программу закрывал?
demas
И потом, первым же скриптом я успешно удаляю записи.
Потом отдельным скриптом вставляю записи, завершаю его. А вторым (с созданием нового объекта) удалить уже не получается.
Или дело все-таки в Object States и я просто не понимаю чего-то глобального?
j2a
Человек, ты во втором примере создаешь новый объект (new_product = bla-bla) с такими же данными, как у старого. И новый несохраненный объект пытаешься удалить.
demas
j2a
Человек, ты во втором примере создаешь новый объект (new_product = bla-bla) с такими же данными, как у старого. И новый несохраненный объект пытаешься удалить.
Ага. Именно это я и пытаюсь сделать :) Я просто удивлен, что здесь возникла проблема.

Ведь в моем новом объекте есть вся необходимая информация, чтобы удалить запись из базы. Теоретически sqlAlchemy может по маппингу определить какие поля в таблице ключевые и сгенерить delete from table where field = object.property. Но она так и не делает.

Отсюда и вопрос - если у меня нет объекта считанного из базы, но есть вся информация, необходимая для того чтобы создать его точную копию (все поля объектов совадают) я все равно должен вычитывать объект из базы перед его удалением. Так?
demas
Все равно у меня не выходит…

    	session = Session()
id = self.get_selected_product().name
print id
orig = session.query(Product).filter(Product.name==id).first()
print orig.name
session.delete(orig)
session.commit()
session.flush()
Здесь:

* в self.get_selected_product() я считываю с интерфейса поля и порождаю новый экземпляр объекта Product (просто у меня уже был такой метод).
* print id я убеждаюсь, что у меня есть правильный id
* orig = session.query(Product).filter(Product.name==id).first() - вычитываю объект из базы
* delete() пытаюсь его удалить

Не удаляется !!! При этом в лог пишет:

two
2008-10-15 17:51:07,927 INFO sqlalchemy.engine.base.Engine.0x..0c UPDATE product SET name=?, category=?, fat=?, protein=?, carbo=? WHERE product.name = ?
2008-10-15 17:51:07,928 INFO sqlalchemy.engine.base.Engine.0x..0c
2008-10-15 17:51:07,930 INFO sqlalchemy.engine.base.Engine.0x..0c COMMIT

Почему update ???
bw
Не знаю почему.
У тебя как минимум должно быть две строки “two”, если судить поприведенному коду. Вывод - это выхлоп другого кода.
Ты уверен, что после создания объекта ты делаешь flush/commit (flush, кстати, идет перед commit, после commit он теряет свой смысл, а commit используется, только если у тебя транзакция, похоже так оно и есть, иначе СУБД выдают ошибку, что транзакция не была начата)? Я вот про это “и порождаю новый экземпляр объекта Product (просто у меня уже был такой метод)”, в приведенном коде ты ничего не порождаешь.

> Ага. Именно это я и пытаюсь сделать :) Я просто удивлен, что здесь возникла проблема.
А я удивлен, что ты удивлен. Раньше, при использовании ORM, объект обязательно нужно было грузить, сейчас можно сделать:
session = Session()
session.query(Product).filter_by(id = 1).delete()
session.flush() # session.commit()
(Кажется в таком случае объект не будет грузиться. Лень в документацию лезть, точно не скажу.)

Еще раз по первому посту: Ты не можешь сделать session.delete() для объекта, если объект не “подключен” к сессии. Он должен быть загружен из базы в этой сессии, либо появиться в ней каким-то другим способом (их несколько).

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

..bw
j2a
demas
j2a
Человек, ты во втором примере создаешь новый объект (new_product = bla-bla) с такими же данными, как у старого. И новый несохраненный объект пытаешься удалить.
Ага. Именно это я и пытаюсь сделать :) Я просто удивлен, что здесь возникла проблема.

Ведь в моем новом объекте есть вся необходимая информация, чтобы удалить запись из базы. Теоретически sqlAlchemy может по маппингу определить какие поля в таблице ключевые и сгенерить delete from table where field = object.property. Но она так и не делает.

Отсюда и вопрос - если у меня нет объекта считанного из базы, но есть вся информация, необходимая для того чтобы создать его точную копию (все поля объектов совадают) я все равно должен вычитывать объект из базы перед его удалением. Так?
Если в рамках ORM, то нужно чтобы связь объект<->запись БД была установлена. Если объект в состоянии pending, он не связан ни с какой записью в БД. Но ты можешь сделать что хочешь средствами SQL expression language.

P.S. А в чем сермяжная правда? Какой смысл делать “копию” объекта для удаления из БД? Почему не воспользоваться самим объектом?
demas
bw
Не знаю почему.
Ок, буду разбираться дальше.

bw
У тебя как минимум должно быть две строки “two”, если судить поприведенному коду.
Почему 2? Поле где “two” это вообще первичный ключ.

bw
Ты уверен, что после создания объекта ты делаешь flush/commit (flush, кстати, идет перед commit, после commit он теряет свой смысл, а commit используется, только если у тебя транзакция, похоже так оно и есть, иначе СУБД выдают ошибку, что транзакция не была начата)?
Я вот про это “и порождаю новый экземпляр объекта Product (просто у меня уже был такой метод)”, в приведенном коде ты ничего не порождаешь.
    def get_selected_product(self):
(model, iter) = self.treeview.get_selection().get_selected()
return Product(self.treestore.get_value(iter, 0),
self.treestore.get_value(iter, 1),
self.treestore.get_value(iter, 2),
self.treestore.get_value(iter, 3),
self.treestore.get_value(iter, 4))
Здесь просто считываются поля из интерфейса и порождается объект.

bw
p.s. И если ты при создании указываешь те же атрибуты атрибуты, что и у сушествующего, ты таким образом не ссылаешься на существующий, ты просто создаешь идентичный (при попытке сохранения такого объекта у тебя возникнут ожиданные проблемы с уникальными ключами).
Угу, понял. Спасибо.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB