【问题标题】:DeleteView with confirmation template and POST method带有确认模板和 POST 方法的 DeleteView
【发布时间】:2015-10-28 20:34:07
【问题描述】:

当我尝试使用 DeleteView 和 POST 方法一次删除模型的多个对象时,我认为我正在执行标准操作,中间有一个确认模板。

好吧,要么我在电脑前坐得太久,要么 Django 不直接支持这种所谓的标准方式。

正如Djangos docs 和其他帖子所说,只有在我使用 GET 方法时才会显示确认模板(带有确认按钮)。但在我的情况下,我有一个 ListView,其中包含我模型的所有对象,第一列是复选框,其值对应于相应对象的 ID。 我可以一次检查多个复选框,然后单击我的“删除选定项目”。表单使用 POST 方法(我不想使用 GET)。

现在:在 POST 方法的情况下,让 DeleteView 与确认模板一起工作似乎会引起一些黑客攻击。几个小时后我没有成功。

这里最好的方法是什么?

我的班级的标题是这样的:

class SomeItemConfirmDeleteView(DeleteView):
    template_name = 'confirm_delete_someitems.html'
    model = SomeItem
    success_url = reverse_lazy('list_someitems_url')
    items_to_delete = []

目前已完成的步骤:

  1. 我重写了 POST 方法,以便如果我有一个列表,其中包含来自选中复选框的所有要删除的 ID,我调用 GET 方法以便显示确认模板。否则,confirm_delete_someitems.html 中的“确认删除”按钮已被按下。

    def post(self, request, *args, **kwargs):
        self.items_to_delete = self.request.POST.getlist('itemsToDelete')
        if not self.items_to_delete:
            return self.delete(request, *args, **kwargs)
        else:
            return self.get(self, *args, **kwargs)
    
  2. 我重写了 get_object 方法

    def get_object(self, queryset=None):
        return self.get_queryset()
    
  3. 我重写了 get_queryset 方法,以便将要删除的对象显示在 confirm_delete_someitems.html 的列表中。我从名为“itemsToDelete”的选中复选框中获取对象。

    def get_queryset(self):
        if not self.items_to_delete:
            queryset = super(ChargeParkConfirmDeleteView, self).get_queryset()
            self.queryset = # ... HOW TO GET THE OBJECTS TO DELETE??
            return self.queryset
        else:
            queryset = super(SomeItemConfirmDeleteView, self).get_queryset()
            self.queryset = queryset.filter(id__in=self.items_to_delete)
            return self.queryset
    

最后一步是棘手的​​地方:如何获取要从 confirm_delete_someitems.html 表单中删除的对象:

<form action="" method="post">
        {% csrf_token %}
        {% trans 'The following objects as well as their related objects will be deleted. Are you sure?' %}
        <ul>
            {% for item in object %}
                <li>{{ item }}</li>
            {% endfor %}
        </ul>
        <input type="submit" value="{% trans 'Confirm deletion' %}" />
    </form>

【问题讨论】:

  • 该模板代码是您的实际模板代码吗?我没有看到你提到的复选框。
  • 这是confirm_delete_someitems.html的模板代码。复选框所在的另一个模板在这里并不重要。

标签: django post confirmation


【解决方案1】:

我现在找到了一个解决方案:我基本上添加了隐藏的输入字段,这些字段再次传输 POST 请求中选中复选框的 ID。

但如果有人找到更优雅的方式,我愿意接受建议。 :)

views.py

class SomeItemConfirmDeleteView(DeleteView):
    template_name = 'confirm_delete_someitems.html'
    model = SomeItem
    success_url = reverse_lazy('list_someitems_url')
    items_to_delete = []

    def get_queryset(self):
        queryset = super(ChargeParkConfirmDeleteView, self).get_queryset()
        self.queryset = queryset.filter(id__in=self.items_to_delete)
        return self.queryset

    def get_object(self, queryset=None):
        return self.get_queryset()

    def post(self, request, *args, **kwargs):
        self.items_to_delete = self.request.POST.getlist('itemsToDelete')
        if self.request.POST.get("confirm_delete"):
            # when confirmation page has been displayed and confirm button pressed
            queryset = self.get_queryset()
            queryset.delete() # deleting on the queryset is more efficient than on the model object
            return HttpResponseRedirect(self.success_url)
        elif self.request.POST.get("cancel"):
            # when confirmation page has been displayed and cancel button pressed
            return HttpResponseRedirect(self.success_url)
        else:
            # when data is coming from the form which lists all items
            return self.get(self, *args, **kwargs)

confirm_delete_someitems.html:

<form action="" method="post">
    {% csrf_token %}
    {% trans 'The following objects as well as their related objects will be deleted. Are you sure?' %}
    <ul>
        {% for item in object %}
            <input type="hidden" value="{{ item.id }}" name="itemsToDelete" />
            <li><a href="{{ item.get_absolute_url }}">{{ item }}</a></li>
        {% endfor %}
    </ul>
    <input type="submit" class="btn btn-primary" value="{% trans 'Confirm deletion' %}" name="confirm_delete" />
    <input type="submit" class="btn btn-primary" value="{% trans 'Cancel' %}" name="cancel"/>
</form>

【讨论】:

    【解决方案2】:
    $(".delete-link").click(function(){
        confirm_box = confirm("Are you sure?");
        if(confirm_box == true)
            return true;
        else
            return false;
    })
    

    【讨论】:

      【解决方案3】:

      谢谢马克

      这对我真的很有帮助。我还想通过 post 方法获得一些基于通用类的视图,例如 DeleteView。但是,我必须更改一些内容,并且我想在此处添加此内容,如果其他像我一样对 Python 了解有限的人会寻找解决方案。

      我的 html 模板的一部分:

          <form method="post">{% csrf_token %}
                              <div class="form-group">
                                      Sure, you want to delete that object?<br>
                                      <br>
                                      <strong>{{ object }}</strong>
                                      {{ form.errors }}
                                      <br>
                                      <br>
                                      <input type="hidden" name="confirm_delete" value="confirm_delete">
                                      <button type="submit" class="btn btn-primary">Delete</button>
                              </div>
                      </form>
      

      和我的部分观点.py

      class MV_Loeschen(DeleteView):
          template_name = templ_folder_name + 'mv_loeschen.html'
          model = MV
          success_url = reverse_lazy(url_app_name + 'mv_ausgabe_alle')
      
          def get_object(self, queryset=None):
              self.queryset = MV.objects.get(mv_id = self.to_delete)
              return self.queryset
      
          def post(self, request, mvpk):
              self.to_delete = mvpk
              if self.request.POST.get("confirm_delete"):
                  queryset = MV.objects.get(mv_id = mvpk)
                  queryset.delete()
                  return HttpResponseRedirect(self.success_url)
              else:
                  return self.get(self, mvpk)
      

      那么,我在这里做什么? def post() 方法向 MV_Loeschen 解释了如何处理 post 请求。我通过发布表单从另一个页面收到参数 mvpk,在该表单中我告诉 Django 我想转到一个视图,以便删除 mvpk 中具有 id 的 MV 对象。

      然后我将 self.to_delete 设置为包含该 id (mvpk)。我稍后在另一个def中需要它。然后我必须看看我是否刚刚到达确认页面(你真的要删除它吗?)或者我是否已经确认我要删除该对象。第一种情况最后由 else 叉子(或者你怎么称呼它)处理。这似乎在内部引发了对 DeleteView 的调用,但使用的是 GET 方法。所以我看了这个

      https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-editing/#django.views.generic.edit.DeleteView
      

      还有我python/site-packages/subfolders中的代码。

      def get 反过来使用 get_object 方法。但是这个 def get_object 不知道 mvpk/我的 MV 对象的 id。所以,我从 self.to_delete 得到这个(因此我需要之前分配它)。在这里,我采取了与 Marc 不同的方法。

      正如他的解决方案get_object()调用get_queryset(),它返回一个查询集,我没有理解他的解决方案中的超行,我只是在get_object()中直接获取查询集。

      所以回到 def post()。如果我已经确认要删除该对象,则必须获取该参数。我这样做:

      self.request.POST.get("confirm-delete")
      

      再次感谢 Marc,我想知道为什么我无法访问:

      request.POST['confirm-delete']
      

      直接。我不确定我现在是否完全理解了这一点,但至少你帮助我完成了这项工作。

      那么我可能在查询集的新设置中有多余的一行。我不知道。然后我分别删除查询集或MV对象。

      最后我重定向到success_url,为此我不得不从django.http导入HttpResponseRedirect

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-14
        • 2013-10-01
        • 2017-08-27
        • 2022-01-15
        • 2012-08-30
        • 2017-08-17
        • 1970-01-01
        • 2013-01-02
        相关资源
        最近更新 更多