improved deletion of recipes

This commit is contained in:
vabene1111 2021-11-04 12:27:21 +01:00
parent 980dc48eb8
commit 1fad1d2b8f
3 changed files with 62 additions and 28 deletions

View File

@ -458,6 +458,9 @@ class Step(ExportModelOperationsMixin('step'), models.Model, PermissionModelMixi
from cookbook.helper.template_helper import render_instructions from cookbook.helper.template_helper import render_instructions
return render_instructions(self) return render_instructions(self)
def __str__(self):
return f'{self.pk} {self.name}'
class Meta: class Meta:
ordering = ['order', 'pk'] ordering = ['order', 'pk']
indexes = (GinIndex(fields=["search_vector"]),) indexes = (GinIndex(fields=["search_vector"]),)

View File

@ -22,13 +22,11 @@
</div> </div>
{{ form|crispy }} {{ form|crispy }}
{% if related_objects %} {% if protected_objects %}
{% blocktrans %} <i>{{ object }}</i> could not be deleted because it is still referenced by the following instances: {% endblocktrans %} <h5>{% trans 'Protected' %} <small class="text-muted">The object you are trying to delete is <b>protected</b> by the following references to it.</small></h5>
<br/> {% for o in protected_objects %}
<br/>
{% for o in related_objects %}
{% class_name o.model as name %} {% class_name o.model as name %}
<h5>{{ name }}</h5> <u>{{ name }}</u>
<ul> <ul>
{% for e in o %} {% for e in o %}
<li> <li>
@ -36,14 +34,40 @@
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endfor %} {% endfor %}
<br/>
{% endif %} {% endif %}
<button class="btn btn-success" type="submit" href="{{ success_url }}"><i {% if cascading_objects %}
<h5>{% trans 'Cascade' %} <small class="text-muted">The object you are trying to delete is used by the following objects which will <b>also be deleted</b>.</small></h5>
{% for o in cascading_objects %}
{% class_name o.model as name %}
<u>{{ name }}</u>
<ul>
{% for e in o %}
<li>
<span class="badge badge-info">#{{ e.id }}</span> {{ e }}
</li>
{% endfor %}
</ul>
{% endfor %}
{% endif %}
{% if set_null_objects %}
<h5>{% trans 'Remove' %} <small class="text-muted">The object you are trying to delete is used by the following objects from which the reference will be removed.</small></h5>
{% for o in set_null_objects %}
{% class_name o.model as name %}
<u>{{ name }}</u>
<ul>
{% for e in o %}
<li>
<span class="badge badge-info">#{{ e.id }}</span> {{ e }}
</li>
{% endfor %}
</ul>
{% endfor %}
{% endif %}
<button class="btn btn-success" type="submit" href="{{ success_url }}" {% if protected_objects %}disabled{% endif %}><i
class="fas fa-trash-alt"></i> {% trans 'Confirm' %}</button> class="fas fa-trash-alt"></i> {% trans 'Confirm' %}</button>
<a href="javascript:history.back()" class="btn btn-danger"><i class="fas fa-undo-alt"></i> {% trans 'Cancel' %} <a href="javascript:history.back()" class="btn btn-danger"><i class="fas fa-undo-alt"></i> {% trans 'Cancel' %}
</a> </a>

View File

@ -1,4 +1,5 @@
from django.contrib import messages from django.contrib import messages
from django.db import models
from django.db.models import ProtectedError from django.db.models import ProtectedError
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
@ -24,30 +25,36 @@ class RecipeDelete(GroupRequiredMixin, DeleteView):
success_url = reverse_lazy('index') success_url = reverse_lazy('index')
def delete(self, request, *args, **kwargs): def delete(self, request, *args, **kwargs):
obj = self.get_object() self.object = self.get_object()
# TODO make this more generic so that all delete functions benefit from this
related_objects = [] if self.get_context_data()['protected_objects']:
for x in obj._meta.get_fields(): return render(request, template_name=self.template_name, context=self.get_context_data())
try:
related = x.related_model.objects.filter(**{x.field.name: obj})
if related.exists():
related_objects.append(related)
except AttributeError:
pass
if related_objects:
self.object = obj
return render(request, template_name=self.template_name, context=self.get_context_data(related_objects=related_objects))
success_url = self.get_success_url() success_url = self.get_success_url()
obj.delete() self.object.delete()
return HttpResponseRedirect(success_url) return HttpResponseRedirect(success_url)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RecipeDelete, self).get_context_data(**kwargs) context = super(RecipeDelete, self).get_context_data(**kwargs)
context['title'] = _("Recipe") context['title'] = _("Recipe")
if 'related_objects' in kwargs:
context['related_objects'] = kwargs.pop('related_objects') # TODO make this more generic so that all delete functions benefit from this
self.object = self.get_object()
context['protected_objects'] = []
context['cascading_objects'] = []
context['set_null_objects'] = []
for x in self.object._meta.get_fields():
try:
related = x.related_model.objects.filter(**{x.field.name: self.object})
if related.exists() and x.on_delete == models.PROTECT:
context['protected_objects'].append(related)
if related.exists() and x.on_delete == models.CASCADE:
context['cascading_objects'].append(related)
if related.exists() and x.on_delete == models.SET_NULL:
context['set_null_objects'].append(related)
except AttributeError:
pass
return context return context