Уведомления

Группа в Telegram: @pythonsu

#1 Апрель 26, 2010 00:59:31

Bdfy1
От:
Зарегистрирован: 2009-11-03
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

связи в django-ORM

Как заставить Django не делать тот бред ( т е каскадные удаления апдейты и прочее ) который django пытается сделать считая себя умнее чем связи в БД при удалении записи ?



Офлайн

#2 Апрель 26, 2010 07:25:05

Александр Кошелев
От: Москва
Зарегистрирован: 2007-02-03
Сообщения: 1724
Репутация: +  2  -
Профиль   Отправить e-mail  

связи в django-ORM

А вы хотите данные неконсистентными сделать?



Офлайн

#3 Апрель 26, 2010 09:09:36

Bdfy1
От:
Зарегистрирован: 2009-11-03
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

связи в django-ORM

Я хочу чтобы целостностью данных занималась БД. Т е когда хочу удалить свойство чтобы не удалялось каскадом полбазы в то время как в базе там стоит on delete restrict, а django мне пытается подсунуть on cascade delete. Кстати конечно хорошо написать столько кода который этот процесс эмулировал но нафига было это делать ? Уж лучше бы добавили много других полезных фич.



Отредактировано (Апрель 26, 2010 09:19:50)

Офлайн

#4 Апрель 26, 2010 09:41:38

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

связи в django-ORM

Очень вероятно у вас какой-то косяк в проектировании моделей)

Но можно проставить значение ключа в None перед удалением, например.

Или еще что-то тут:
http://docs.djangoproject.com/en/dev/ref/models/relations/
QuerySet.remove
QuerySet.clear



Офлайн

#5 Апрель 26, 2010 10:38:17

Bdfy1
От:
Зарегистрирован: 2009-11-03
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

связи в django-ORM

Очень вероятно у вас какой-то косяк в проектировании моделей)
Вы о чем ? Представьте 3 сущности - свойсва + модель+типы свойста. Соотв в интерфейсе на джанго 3 таблицы. В базе стоит соотв чтобы при попытке удалить тип свойства “отсылалось лесом”. В интерфейсе можно конечно проверять при попытке удаления но извините зачем это делать когда в базе все это учтены. И тут вмешивается великий ORM от Django который пытается этот “недостаток” устранить. В результате полбазы нет т к была попытка удалить тип свойства. В чем косяк то ?
Вон кстати тикет висит до сих пор:
http://code.djangoproject.com/ticket/7539

А решение хакообразное:

technology = models.ForeignKey(Technology,null=True, blank=True)



Отредактировано (Апрель 26, 2010 10:39:38)

Офлайн

#6 Апрель 26, 2010 11:23:30

Evg
От:
Зарегистрирован: 2008-12-25
Сообщения: 346
Репутация: +  -1  -
Профиль   Отправить e-mail  

связи в django-ORM

Это еще спорный вопрос кто за целостностью должен следить бд или орм, если вы используете орм)
а какой смысл от свойств у которых нет типа?) по моему логично удаляет)



Офлайн

#7 Апрель 26, 2010 12:00:45

Александр Кошелев
От: Москва
Зарегистрирован: 2007-02-03
Сообщения: 1724
Репутация: +  2  -
Профиль   Отправить e-mail  

связи в django-ORM

Bdfy1
В чем косяк то ?
В ДНК.

Если не хотите чтобы типы свойств удалялись, то не удаляете. Перегрузите методы и сделайте чтобы они не удаляли объект.

Такая логика в БД – зло.

Bdfy1
А решение хакообразное:

technology = models.ForeignKey(Technology,null=True, blank=True)
Где здесь хак?



Офлайн

#8 Апрель 26, 2010 14:22:04

Bdfy1
От:
Зарегистрирован: 2009-11-03
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

связи в django-ORM

де здесь хак?
В том что связи предполагаются null что в общем-то не так. Если уж django ORM захотело копировать ON CASCADE DELETE то зачем это делать по умолчанию а не сделать опцией ? Причем если посмотреть генерируемые sql запросы при таком удалении - много интересного там можно найти :).

В ДНК.


Такая логика в БД – зло.
ДНК не ДНК но если с БД работает не только один интерфейс а что-то еще написанное на чем угодно - куда же еще такую логику не засунуть как в БД.

Если не хотите чтобы типы свойств удалялись, то не удаляете. Перегрузите методы и сделайте чтобы они не удаляли объект.
Я хочу чтобы типы свойств удалялись только те которые можно удалить - т е например типы которые не используются в моделях. Вот и все.



Отредактировано (Апрель 26, 2010 14:22:49)

Офлайн

#9 Апрель 26, 2010 14:58:59

regall
От: Киев
Зарегистрирован: 2008-07-17
Сообщения: 1583
Репутация: +  3  -
Профиль   Отправить e-mail  

связи в django-ORM

Bdfy1, если вашу БД используют другие программы кроме django, причем во всякой извращенной форме (имеются в виду особенности, которые вы описали в предыдущем посте), то вам лучше смотреть в сторону SQLAlchemy, и отказаться от django в пользу, например, TG, или Pylons, которые с алхимией работают по умолчанию и рекомендациям. Все-таки django-ORM разрабатывался как часть django, а не как отдельный ORM, он удовлетворяет тем требованиям, которые на него возложены, и никаким другим.



Отредактировано (Апрель 26, 2010 15:00:23)

Офлайн

#10 Июнь 1, 2010 04:20:03

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

связи в django-ORM

Ответы местных гуру просто впечатляют. Такое ощущение что никто ни разу не использовал ON DELETE RESTRICT:
* Evg: Очень вероятно у вас какой-то косяк в проектировании моделей)
* Daevaorn: Косяк в … ДНК
* Daevaorn: Такая логика в БД – зло.
* regall: вашу БД используют другие программы кроме django, причем во всякой извращенной форме

Тут хочется заметить что если ON DELETE RESTRICT явно ( mysql, postgresql ) или неявно ( oracle, mssql ) присутствует в большинстве нормальных баз, то наверное он злом или ошибкой в днк являться не может. Это так же глупо, как утверждать что крестовых отверток не существует, есть только плоские, только потому что вы не хотите пользоваться крестовой ( ужос ) :) А касательно кривости структуры и применимости этого поведения - ну вот хочу я чтобы запись можно было удалить только если на неё нет ссылок, мне удавиться или использовать другой фрейворк?

Отдельно порадовал ответ regall - “Все-таки django-ORM разрабатывался как часть django, а не как отдельный ORM, он удовлетворяет тем требованиям, которые на него возложены, и никаким другим.” Фраза ни о чем и полностью отражает подпись под этим постом. Кстати, было бы неплохо посмотреть на ссылочку, где расписана цель и задачи джанго орм.

Ответ lorien вообще является образцом “дружелюбия”. Новичкам не рады?

Да, собственно о чем я… Я не ругаться и не высказывать свое фи пришел. Просто каждый раз когда искал решение по эмуляции рестрикта наталкивался именно на эту страничку, потому решил на фоне прочих “фи” запечатлеть таки действенное решение - мало ли кто еще набредет. Впрочем, решений тонна.

Исходная задача - эмуляция ON DELETE RESTRICT, что в переводе на русский - запретить удаление объектов, на которые есть ссылки.

1. Перегрузить метод delete у models.Manager

Реализуемо, но меньше всего хотелось бы этим заниматься, поскольку model.Manager это практически полностью прокси к QuerySet, и фактически прийдется переписывать соответствующий метод именно у queryset, а там все не так тривиально, хоть и возможно. Вобщем отмел как геморный.

2. Перегрузить метод delete у models.Model

А вот тут как раз ничего сложного. Оригинальный код:

    def delete(self, using=None):
using = using or router.db_for_write(self.__class__, instance=self)
assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)

# Find all the objects than need to be deleted.
seen_objs = CollectedObjects()
self._collect_sub_objects(seen_objs)

# Actually delete the objects.
delete_objects(seen_objs, using)
Его без проблем можно скопировать в класс-наследник и вставить проверку на количество seen_objs с выбросом исключения в случае > 1 .

Потенциальных минусов тут два:
а) если в будущем код delete из базового класса изменится, то наш может стать не актуальным.
б) Кажется была проблема с вызовом mode.delete() из queryset.delete() в некоторых случаях и я так и не понял решили её или нет.

3. Хуки\сигналы наше все.

Нужно определить какой-то универсальный обработчик удаления и приаттачить его ко всем моделям - будет счастье. Причем “счастье” лишено минусов из пункта 2, но обладает своим - снижение наглядности. Сам сигнал объявляется отдельно от модели и можно банально его не заметить при небрежном просмотре кода. Впрочем, кто сказал что к коду нужно относиться небрежно :)

Ну и собственно пример такого обработчика:
from django.db.models.signals import pre_delete
from django.db.models.query_utils import CollectedObjects
from django.db.utils import IntegrityError

def on_delete_restrict( sender, **kwargs ):
# Find all the objects than need to be deleted.
seen_objs = CollectedObjects()
kwargs['instance']._collect_sub_objects(seen_objs)
if len(seen_objs.data) > 1:
raise IntegrityError('Some objects are still depends on %s(pk=%s)' % ( str(kwargs['instance'].__class__.__name__), str(kwargs['instance'].pk) ) )


pre_delete.connect(on_delete_restrict, sender = Model1)
pre_delete.connect(on_delete_restrict, sender = Model2)
pre_delete.connect(on_delete_restrict, sender = Model3)
Итого - для эмуляции ON DELETE RESTRICT потребутся определить один обработчик и подкинуть его на pre_delete для _нужных_ моделей.

Что тут можно добавить… Вообще эмуляция on_delete_restrict не отменяет необходимости обработки соответствующей ситуации, дабы банально не выдавать юзеру непонятные мессаги. С другой стороны, теперь мы спокойны что юзер по тупняку не грохнет полбазы при удалении, как ему показалось, лишней записи из таблицы-справочника.



Отредактировано (Июнь 1, 2010 04:24:23)

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version