【问题标题】:Django IndexError: pop from empty list within DeleteViewDjango IndexError:从 DeleteView 中的空列表中弹出
【发布时间】:2020-01-28 15:42:24
【问题描述】:

我正在尝试从我的 Django 应用程序的数据库中删除一个对象。

这个想法是从 html 文件中获取主要内容并将其发布到表单中。我不明白我应该如何传递主键以正确的方式发布我的删除请求。

我在 stackoverflow、django doc 和其他来源上找到了关于基于类的视图 DeleteView 的所有内容,但没有弄清楚它是如何工作的。

例如: Django delete FileField

How to delete a record in Django models?

Python Django delete current object

How to delete a record in Django models?

https://docs.djangoproject.com/en/2.2/topics/db/queries/

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

在代码的主要 sn-ps 下方,如果您缺少需要的内容,请告诉我。

views.py

class SelectFileDelView(TemplateView):
    """
    This view is used to select a file from the list of files in the server.
    After the selection, it will send the file to the server.
    The server will then delete the file.
    """
    template_name = 'select_file_deletion.html'
    parser_classes = FormParser
    queryset = FileModel.objects.all()

    def get_context_data(self, **kwargs):
        """
        This function is used to render the list of files in the MEDIA_ROOT in the html template
        and to get the pk (primary key) of each file.
        """
        context = super().get_context_data(**kwargs)
        media_path = settings.MEDIA_ROOT
        myfiles = [f for f in listdir(media_path) if isfile(join(media_path, f))]
        pk_list = []
        for value in myfiles:
            pk = FileModel.objects.filter(file=value).values_list('pk', flat=True)
            pk_list.append(pk)
        file_and_pk = zip(myfiles, pk_list)
        context['filename'] = file_and_pk
        return context


class FileDeleteView(DeleteView):
    """
    This class contains the method to delete a file interacting directly with the API.
    DELETE requests are accepted.
    """
    model = FileModel
    fields = ['file']
    template_name = 'delete_success.html'
    success_url = '/delete_success/'

    def post(self, request):
        """
        This method is used to making predictions on audio files
        loaded with FileView.post
        """
        pk = request.POST.getlist('pk').pop()
        try:
            return Response(pk, status=status.HTTP_200_OK)
        except ValueError as err:
            return Response(str(err), status=status.HTTP_400_BAD_REQUEST)

select_file_deletion.html

{% extends "index.html" %}

{% block content %}
    <form action="/App/delete/" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        {{ form.as_p }}
        <h5>Please select one file at a time from the list below to delete it from the server.</h5>
        {% for myfile, pk in filename %}
            <p>Are you sure you want to delete "{{ myfile }}"?</p>
            <input type="submit" value="Confirm">
            <input type="hidden" name="pk" value="{{ pk }}">
            <br>
        {% endfor %}
        <br>
    </form>
{% endblock %}

urls.py

urlpatterns = [

    # Url to select a file to be deleted and confirm the upload
    url('filedelete/', SelectFileDelView.as_view(), name='file_delete'),
    url('delete_success/(?P<pk>\d+)/$', FileDeleteView.as_view(), name='delete_success'),

]

models.py

"""
Models.py includes the database structure of the application.
"""

from django.db import models
from django.conf import settings
from django.dispatch import receiver
from django.db.models.signals import post_delete


class FileModel(models.Model):
    file = models.FileField(null=True, blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    path = models.FilePathField(path=settings.MEDIA_ROOT, default=settings.MEDIA_ROOT)


@receiver(post_delete, sender=FileModel)
def submission_delete(sender, instance, **kwargs):
    """
    This function is used to delete attachments when a file object is deleted.
    Django does not do this automatically.
    """
    instance.file.delete(False)

错误

IndexError at /App/delete/
pop from empty list
Request Method: POST
Request URL:    http://127.0.0.1:8000/App/delete/
Django Version: 2.2.4
Exception Type: IndexError
Exception Value:    
pop from empty list
Exception Location: /Users/marcogdepinto/PycharmProjects/DjangoRestDeepLearning/App/views.py in post, line 131
Python Executable:  /Users/marcogdepinto/anaconda3/bin/python
Python Version: 3.6.9

UPDATE1:html 已更改如下

<input type="hidden" name="pk" value="{{ pk }}">

这样做,我得到一个

AssertionError at /App/delete/
.accepted_renderer not set on Response

完整的追溯如下:

Environment:

Request Method: POST
Request URL: http://127.0.0.1:8000/App/delete/

Django Version: 2.2.4
Python Version: 3.6.9
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'rest_framework',
 'App',
 'debug_toolbar']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware']



Traceback:

File "/Users/marcogdepinto/anaconda3/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/Users/marcogdepinto/anaconda3/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  145.                 response = self.process_exception_by_middleware(e, request)

File "/Users/marcogdepinto/anaconda3/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  143.                 response = response.render()

File "/Users/marcogdepinto/anaconda3/lib/python3.6/site-packages/django/template/response.py" in render
  106.             self.content = self.rendered_content

File "/Users/marcogdepinto/anaconda3/lib/python3.6/site-packages/rest_framework/response.py" in rendered_content
  55.         assert renderer, ".accepted_renderer not set on Response"

Exception Type: AssertionError at /App/delete/
Exception Value: .accepted_renderer not set on Response

【问题讨论】:

  • 您可以将print(request.POST.getlist('pk')) 添加到您的帖子视图中吗?我假设这会返回一个空列表。
  • 此外,为此发送DELETE 请求而不是POST 请求更有意义,但如果此视图仅用于删除项目,则无关紧要。
  • 您好,感谢您的回答。 print(request.POST.getlist('pk')) 返回空,这就是问题所在,我不明白如何通过表单传递 pk
  • 我添加了一个更新。希望对您有所帮助!

标签: python django post http-delete


【解决方案1】:

request.POST 是表单输入的相应名称/值的键/值对的 QueryDict

我认为问题在于您忘记在pk 输入中添加name,因此当您的视图获取request.POST 对象时,没有一个名为pk 的键。

如果没有找到名为arg 的键,.getlist('arg') 将返回一个空列表,并且没有给出默认值,这会导致您得到错误。

这应该可以解决您的问题:

<input type="hidden" name="pk" value="{{ pk }}">

更新

我相信您遇到的错误与您的原始问题无关,可能应该作为一个新问题提出。话虽如此,我仍然会尽力提供帮助,我只是没有使用 DRF 的经验。

根据docs

.accepted_renderer

将用于渲染响应的渲染器实例。 在视图返回响应之前由 APIView 或 @api_view 自动设置。

还有:

除非您出于某种原因想要大量自定义 REST 框架,否则您应该始终对返回 Response 对象的视图使用 APIView 类或 @api_view 函数。这样做可确保视图在从视图返回之前执行内容协商并为响应选择适当的渲染器。

我认为您最好的选择是使用 @api_view 装饰器(尽管我不确定这是否适用于基于类的视图)。

from rest_framework.decorators import api_view
from rest_framework.response import Response

class FileDeleteView(DeleteView):

    model = FileModel
    fields = ['file']
    template_name = 'delete_success.html'
    success_url = '/delete_success/'

    @api_view
    def post(self, request):
    ...

【讨论】:

  • 嗨,以这种方式更改值现在我有一个'AssertionError at /App/delete/.accepted_renderer not set on Response'
  • @MarcoG.dePinto 你能显示完整的回溯吗?以前从未见过该错误。
  • 将编辑主要问题,太大而无法留在评论中
  • @MarcoG.dePinto 感谢您先发制人!
  • 好的,traceback现在在主要问题中
猜你喜欢
  • 1970-01-01
  • 2015-09-21
  • 2019-02-17
  • 2013-06-11
  • 1970-01-01
  • 2020-10-19
  • 2014-04-04
  • 1970-01-01
  • 2021-05-13
相关资源
最近更新 更多