Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 14, 2008 16:18:17

demas
От:
Зарегистрирован: 2008-09-10
Сообщения: 60
Репутация: +  0  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

Подскажите, пожалуйста, почему вот такой код работает:

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?



Офлайн

#2 Окт. 14, 2008 16:39:44

j2a
От:
Зарегистрирован: 2006-06-29
Сообщения: 869
Репутация: +  1  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

Нееееее. Читай http://www.sqlalchemy.org/docs/05/session.html#unitofwork_using_states – у тебя новый объект в состоянии pending.



Офлайн

#3 Окт. 14, 2008 16:49:50

demas
От:
Зарегистрирован: 2008-09-10
Сообщения: 60
Репутация: +  0  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

Хм…
Почему новый? Он создан еще вчера и с тех пор я закрывал запущенную программу.

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 я даже программу закрывал?



Офлайн

#4 Окт. 14, 2008 16:56:52

demas
От:
Зарегистрирован: 2008-09-10
Сообщения: 60
Репутация: +  0  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

И потом, первым же скриптом я успешно удаляю записи.
Потом отдельным скриптом вставляю записи, завершаю его. А вторым (с созданием нового объекта) удалить уже не получается.
Или дело все-таки в Object States и я просто не понимаю чего-то глобального?



Офлайн

#5 Окт. 15, 2008 12:32:48

j2a
От:
Зарегистрирован: 2006-06-29
Сообщения: 869
Репутация: +  1  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

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



Офлайн

#6 Окт. 15, 2008 13:43:03

demas
От:
Зарегистрирован: 2008-09-10
Сообщения: 60
Репутация: +  0  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

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

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

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



Офлайн

#7 Окт. 15, 2008 16:53:41

demas
От:
Зарегистрирован: 2008-09-10
Сообщения: 60
Репутация: +  0  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

Все равно у меня не выходит…

    	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 ???



Офлайн

#8 Окт. 15, 2008 17:07:32

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

[sqlalchemy] - удаление объектов

Не знаю почему.
У тебя как минимум должно быть две строки “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



Отредактировано (Окт. 15, 2008 17:09:40)

Офлайн

#9 Окт. 15, 2008 17:09:36

j2a
От:
Зарегистрирован: 2006-06-29
Сообщения: 869
Репутация: +  1  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

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

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

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

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



Отредактировано (Окт. 15, 2008 17:10:13)

Офлайн

#10 Окт. 16, 2008 10:46:25

demas
От:
Зарегистрирован: 2008-09-10
Сообщения: 60
Репутация: +  0  -
Профиль   Отправить e-mail  

[sqlalchemy] - удаление объектов

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. И если ты при создании указываешь те же атрибуты атрибуты, что и у сушествующего, ты таким образом не ссылаешься на существующий, ты просто создаешь идентичный (при попытке сохранения такого объекта у тебя возникнут ожиданные проблемы с уникальными ключами).
Угу, понял. Спасибо.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version