2016-02-11 5 views
3

У меня есть эти модели.Предотвращение каскадирования Django для суперкласса

# models.py 
class A(models.Model): 
    name = models.CharField('Name', max_length=50) 

class B(A): 
    a_ptr = models.OneToOneField('A', primary_key=True, editable=True, parent_link=True) 
    number = models.CharField('Number', max_length=15) 

Отношения я пытаюсь захватить то, что каждый B также А, но А не обязательно B. Я мог бы использовать ForeignKey вместо этого, но я бы предпочел, чтобы обратиться к унаследованным полей на B, например, B.name.

Способ, которым я намереваюсь использовать эти модели, состоит в том, что A всегда будет создаваться в первую очередь. И всякий раз, когда создается экземпляр B, он должен будет выбрать существующий (но еще не принятый) B.

Это работает довольно хорошо до сих пор, но единственная проблема, с которой я столкнулся, - это каскадное удаление. С помощью этой настройки удаление B приведет к удалению соответствующего A (или, по крайней мере, это то, что происходит с администратором django). Как я могу отключить этот каскад?

Мне известно о атрибуте on_delete, но если я установил это, скажем DO_NOTHING в поле a_ptr, это будет иметь эффект, позволяющий B существовать без соответствующих A, а не наоборот.

Как это сделать?

+0

[Этот ответ] (http://stackoverflow.com/questions/3711191/django-deleting-object-keeping-parent) довольно умный (переключите 'b.a_ptr', чтобы указать на другой экземпляр перед удалением). Я не знаю, есть ли менее хакерский путь. – Alasdair

ответ

1

Фактически вы можете передать keep_parents=True методу удаления на вашей модели.

a = A.objects.create(name='a') 
b = B.objects.create(a_ptr=a, number='1') 

b.delete(keep_parents=True) 
assert A.objects.filter(pk=a.pk).exists() 

Примечание: параметр keep_parents был добавлен в Django 1.9. Вероятно, вам понадобится использовать this answer для более ранних версий Django.

+0

Ни один из них не будет поддерживать массовое удаление, правильно? – Khodeir

+0

Правильный метод 'delete' на QuerySets не принимает никаких параметров. Если вам абсолютно необходимо удалить лишний экземпляр, вы можете использовать '_raw_delete' - например. 'B.objects.all() ._ raw_delete (B.objects.db)' - но это не официальный API и может измениться в любой момент. Он также не будет посылать никаких сигналов, и нет защиты для каскадов. –