mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 17:08:41 -06:00
* show objects that would be deleted by cascade
* some items were not showing (eg ips on devices)
* dont include the item being deleted in the list of related items
* Revert "dont include the item being deleted in the list of related items"
This reverts commit 298a7860b2
.
* cleanup
- migrate code to use collector directly instead of the NestedObjects wrapper from admin.utils
- adjust object names and text output
* requested adjustments
* remove comma from end of list
* linting
* refactor, add accordion
* migrate to defaultdict, use title for capitalisation of accordian titles
* Misc cleanup
---------
Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
parent
944008d475
commit
f6338abf14
@ -1,9 +1,11 @@
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from copy import deepcopy
|
||||
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
from django.db import router, transaction
|
||||
from django.db.models import ProtectedError, RestrictedError
|
||||
from django.db.models.deletion import Collector
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.html import escape
|
||||
@ -320,6 +322,27 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
|
||||
def get_required_permission(self):
|
||||
return get_permission_for_model(self.queryset.model, 'delete')
|
||||
|
||||
def _get_dependent_objects(self, obj):
|
||||
"""
|
||||
Returns a dictionary mapping of dependent objects (organized by model) which will be deleted as a result of
|
||||
deleting the requested object.
|
||||
|
||||
Args:
|
||||
obj: The object to return dependent objects for
|
||||
"""
|
||||
using = router.db_for_write(obj._meta.model)
|
||||
collector = Collector(using=using)
|
||||
collector.collect([obj])
|
||||
|
||||
# Compile a mapping of models to instances
|
||||
dependent_objects = defaultdict(list)
|
||||
for model, instance in collector.instances_with_model():
|
||||
# Omit the root object
|
||||
if instance != obj:
|
||||
dependent_objects[model].append(instance)
|
||||
|
||||
return dict(dependent_objects)
|
||||
|
||||
#
|
||||
# Request handlers
|
||||
#
|
||||
@ -333,6 +356,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
|
||||
"""
|
||||
obj = self.get_object(**kwargs)
|
||||
form = ConfirmationForm(initial=request.GET)
|
||||
dependent_objects = self._get_dependent_objects(obj)
|
||||
|
||||
# If this is an HTMX request, return only the rendered deletion form as modal content
|
||||
if is_htmx(request):
|
||||
@ -343,6 +367,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
|
||||
'object_type': self.queryset.model._meta.verbose_name,
|
||||
'form': form,
|
||||
'form_url': form_url,
|
||||
'dependent_objects': dependent_objects,
|
||||
**self.get_extra_context(request, obj),
|
||||
})
|
||||
|
||||
@ -350,6 +375,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView):
|
||||
'object': obj,
|
||||
'form': form,
|
||||
'return_url': self.get_return_url(request, obj),
|
||||
'dependent_objects': dependent_objects,
|
||||
**self.get_extra_context(request, obj),
|
||||
})
|
||||
|
||||
|
@ -12,6 +12,40 @@
|
||||
Are you sure you want to <strong class="text-danger">delete</strong> {{ object_type }} <strong>{{ object }}</strong>?
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% if dependent_objects %}
|
||||
<p>
|
||||
{% trans "The following objects will be deleted as a result of this action." %}
|
||||
</p>
|
||||
<div class="accordion" id="deleteAccordion">
|
||||
{% for model, instances in dependent_objects.items %}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="deleteheading{{ forloop.counter }}">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{ forloop.counter }}" aria-expanded="false" aria-controls="collapse{{ forloop.counter }}">
|
||||
{% with object_count=instances|length %}
|
||||
{{ object_count }}
|
||||
{% if object_count == 1 %}
|
||||
{{ model|meta:"verbose_name" }}
|
||||
{% else %}
|
||||
{{ model|meta:"verbose_name_plural" }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse{{ forloop.counter }}" class="accordion-collapse collapse" aria-labelledby="deleteheading{{ forloop.counter }}" data-bs-parent="#deleteAccordion">
|
||||
<div class="accordion-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
{% for instance in instances %}
|
||||
{% with url=instance.get_absolute_url %}
|
||||
<a {% if url %}href="{{ url }}" {% endif %}class="list-group-item list-group-item-action">{{ instance }}</a>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% render_form form %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
Loading…
Reference in New Issue
Block a user