【问题标题】:How to show related items using DeleteView in Django?如何在 Django 中使用 DeleteView 显示相关项目?
【发布时间】:2012-08-22 22:17:29
【问题描述】:

我正在做一个视图以从模型中删除(使用 Django 的通用视图 DeleteView)一个实例,但它会级联并从其他模型中删除实例:

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

【问题讨论】:

    标签: django view cascade


    【解决方案1】:

    您可以使用 Django 使用的Collector 类来确定要在级联中删除哪些对象。实例化它,然后在其上调用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 包有一个称为NestedObjectsCollector 子类,它的工作方式相同,但有一个返回分层列表的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

    【讨论】:

    • 请注意,Collector 不会解析多对多字段,您需要使用 NestedObjects 来做到这一点。
    【解决方案2】:

    我使用管理员对 get_deleted_objects() 的缩减修改 并使用它在删除视图的 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 复制/粘贴/编辑/删除不需要的内容

    【讨论】:

    • get_context 应该是 get_context_data
    • 这很好用。在具有自引用的多对多上,to_delete 还包含类似“From_company-to_company 关系:Company_contractor 对象 (13)”的内容。这种关系如何正确表现?
    猜你喜欢
    • 2022-01-10
    • 2021-11-27
    • 2021-03-04
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 2021-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多