Подтвердить что ты не робот

Как показать связанные элементы с помощью DeleteView в Django?

Я делаю вид, чтобы удалить (используя общий вид DeleteView из Django) экземпляр из модели, но он каскадирует и удаляет экземпляры из других моделей:

url(r'^person/(?P<pk>\d+)/delete/$', login_required(DeleteView.as_view(model=Person, success_url='/person/', template_name='delete.html')), name='person_delete'),

Что я хочу сделать, так это показать список связанных элементов, которые будут удалены, как это делает интерфейс администратора, например:

Are you sure you are going to delete Person NAMEOFTHEPERSON?
By deleting it, you are also going to delete:
CLASSNAME1: CLASSOBJECT1 ; CLASSNAME2: CLASSOBJECT2 ; CLASSNAME3: CLASSOBJECT3 ; etc
4b9b3361

Ответ 1

Вы можете использовать Collector класс, используемый Django для определения того, какие объекты нужно удалить в каскаде. Выполните его, а затем вызовите collect, передав объекты, которые вы собираетесь удалить. Он ожидает список или набор запросов, поэтому, если у вас есть только один объект, просто введите внутри списка:

from django.db.models.deletion import Collector

collector = Collector(using='default') # or specific database
collector.collect([some_instance])
for model, instance in collector.instances_with_model():
    # do something

instances_with_model возвращает генератор, поэтому вы можете использовать его только в контексте цикла. Если вы предпочитаете фактическую структуру данных, которую вы можете манипулировать, пакет admin contrib имеет подкласс Collector, называемый NestedObjects, который работает одинаково, но имеет метод nested, который возвращает иерархический список:

from django.contrib.admin.utils import NestedObjects

collector = NestedObjects(using='default') # or specific database
collector.collect([some_instance])
to_delete = collector.nested()

Обновлено: Поскольку Django 1.9, django.contrib.admin.util был переименован в django.contrib.admin.utils

Ответ 2

Обновление: из Django 1.9+ NestedObject следует импортировать из django.contrib.admin.util s

    from django.contrib.admin.utils import NestedObjects

Ответ 3

Я использую модификацию вырезания get_deleted_objects() из admin и использовать его для расширения моего контекста в get_context в представлении удаления:

определить где-нибудь

from django.contrib.admin.utils import NestedObjects
from django.utils.text import capfirst
from django.utils.encoding import force_text

def get_deleted_objects(objs): 
    collector = NestedObjects(using='default')
    collector.collect(objs)
    #
    def format_callback(obj):
        opts = obj._meta
        no_edit_link = '%s: %s' % (capfirst(opts.verbose_name),
                                   force_text(obj))
        return no_edit_link            
    #
    to_delete = collector.nested(format_callback)
    protected = [format_callback(obj) for obj in collector.protected]
    model_count = {model._meta.verbose_name_plural: len(objs) for model, objs in collector.model_objs.items()}
    #
    return to_delete, model_count, protected

, то в ваших представлениях

from somewhere import get_deleted_objects
#
class ExampleDelete(DeleteView):
    # ...
    def get_context_data(self, **kwargs):
        #
        context = super().get_context_data(**kwargs)
        #
        deletable_objects, model_count, protected = get_deleted_objects([self.object])
        #
        context['deletable_objects']=deletable_objects
        context['model_count']=dict(model_count).items()
        context['protected']=protected
        #
        return context

теперь вы можете использовать их в своем шаблоне

<table>
  <tr>
    <th>Name</th>
    <th>Amount</th>
  </tr>
  {% for model_name, object_count in model_count %}
    <tr>
      <td>{{ model_name|capfirst }}</td>
      <td>{{ object_count }}</td>
    </tr>
  {% endfor %}
</table>
<p>
  <ul>
    {{ deletable_objects|unordered_list }}
  </ul>
</p>

Большинство из них просто копируют/вставляют/редактируют/удаляют нежелательные из django admin