Django IndexError: pop from empty list within DeleteView

Django IndexError: pop from empty list within DeleteView

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

我们的想法是从 html 文件中获取主文件,然后 post 以表格形式获取。我不明白我应该如何以正确的方式将主键传递给 post 我的删除请求。

我在 Whosebug、django 文档和其他来源上找到了关于 class 基于视图 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

在代码的主要片段下方,如果您缺少需要的东西,请告诉我。

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

request.POSTQueryDict 对 key/value 对相应的 name/value 表单输入。

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

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

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

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

更新

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

根据 docs:

.accepted_renderer

The renderer instance that will be used to render the response. Set automatically by the APIView or @api_view immediately before the response is returned from the view.

还有:

Unless you want to heavily customize REST framework for some reason, you should always use an APIView class or @api_view function for views that return Response objects. Doing so ensures that the view can perform content negotiation and select the appropriate renderer for the response, before it is returned from the 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):
    ...