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/
在代码的主要片段下方,如果您缺少需要的东西,请告诉我。
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.POST
是 QueryDict
对 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):
...
我正在尝试从我的 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/
在代码的主要片段下方,如果您缺少需要的东西,请告诉我。
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.POST
是 QueryDict
对 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):
...