How to show related items using DeleteView in Django?

后端 未结 2 1405
我在风中等你
我在风中等你 2020-11-29 05:03

I am doing a view to delete (using the generic view DeleteView from Django) an instance from a model, but it cascades and deletes instances from other models:



        
相关标签:
2条回答
  • 2020-11-29 05:45

    You can use the Collector class Django uses to determine what objects to delete in the cascade. Instantiate it and then call collect on it passing the objects you intend to delete. It expects a list or queryset, so if you only have one object, just put in inside a list:

    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 returns a generator, so you can only use it within the context of a loop. If you'd prefer an actual data structure that you can manipulate, the admin contrib package has a Collector subclass called NestedObjects, that works the same way, but has a nested method that returns a hierarchical list:

    from django.contrib.admin.utils import NestedObjects
    
    collector = NestedObjects(using='default') # or specific database
    collector.collect([some_instance])
    to_delete = collector.nested()
    

    Updated: Since Django 1.9, django.contrib.admin.util was renamed to django.contrib.admin.utils

    0 讨论(0)
  • 2020-11-29 06:01

    I use a cutdown modifcation of get_deleted_objects() from the admin and use it to extend my context in get_context in the delete view:

    define somewhere

    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
    

    then in your views

    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
    

    now you can use them in your template

    <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>
    

    Most is just copy/paste/edit/delete unwanted from django admin

    0 讨论(0)
提交回复
热议问题