mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #20331 -- Allowed admin actions to serve StreamingHttpResponses
Thanks Edwin.
This commit is contained in:
parent
8010289ea2
commit
d727518ad6
@ -24,6 +24,7 @@ from django.db.models.related import RelatedObject
|
||||
from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
|
||||
from django.db.models.sql.constants import QUERY_TERMS
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||
from django.http.response import HttpResponseBase
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template.response import SimpleTemplateResponse, TemplateResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
@ -1026,10 +1027,10 @@ class ModelAdmin(BaseModelAdmin):
|
||||
|
||||
response = func(self, request, queryset)
|
||||
|
||||
# Actions may return an HttpResponse, which will be used as the
|
||||
# response from the POST. If not, we'll be a good little HTTP
|
||||
# citizen and redirect back to the changelist page.
|
||||
if isinstance(response, HttpResponse):
|
||||
# Actions may return an HttpResponse-like object, which will be
|
||||
# used as the response from the POST. If not, we'll be a good
|
||||
# little HTTP citizen and redirect back to the changelist page.
|
||||
if isinstance(response, HttpResponseBase):
|
||||
return response
|
||||
else:
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
@ -9,11 +9,13 @@ from django.contrib import admin
|
||||
from django.contrib.admin.views.main import ChangeList
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
from django.core.mail import EmailMessage
|
||||
from django.core.servers.basehttp import FileWrapper
|
||||
from django.conf.urls import patterns, url
|
||||
from django.db import models
|
||||
from django.forms.models import BaseModelFormSet
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponse, StreamingHttpResponse
|
||||
from django.contrib.admin import BooleanFieldListFilter
|
||||
from django.utils.six import StringIO
|
||||
|
||||
from .models import (Article, Chapter, Account, Media, Child, Parent, Picture,
|
||||
Widget, DooHickey, Grommet, Whatsit, FancyDoodad, Category, Link,
|
||||
@ -238,8 +240,20 @@ def redirect_to(modeladmin, request, selected):
|
||||
redirect_to.short_description = 'Redirect to (Awesome action)'
|
||||
|
||||
|
||||
def download(modeladmin, request, selected):
|
||||
buf = StringIO('This is the content of the file')
|
||||
return StreamingHttpResponse(FileWrapper(buf))
|
||||
download.short_description = 'Download subscription'
|
||||
|
||||
|
||||
def no_perm(modeladmin, request, selected):
|
||||
return HttpResponse(content='No permission to perform this action',
|
||||
status=403)
|
||||
no_perm.short_description = 'No permission to run'
|
||||
|
||||
|
||||
class ExternalSubscriberAdmin(admin.ModelAdmin):
|
||||
actions = [redirect_to, external_mail]
|
||||
actions = [redirect_to, external_mail, download, no_perm]
|
||||
|
||||
|
||||
class Podcast(Media):
|
||||
|
@ -2432,6 +2432,29 @@ class AdminActionsTest(TestCase):
|
||||
response = self.client.post(url, action_data)
|
||||
self.assertRedirects(response, url)
|
||||
|
||||
def test_custom_function_action_streaming_response(self):
|
||||
"""Tests a custom action that returns a StreamingHttpResponse."""
|
||||
action_data = {
|
||||
ACTION_CHECKBOX_NAME: [1],
|
||||
'action': 'download',
|
||||
'index': 0,
|
||||
}
|
||||
response = self.client.post('/test_admin/admin/admin_views/externalsubscriber/', action_data)
|
||||
content = b''.join(response.streaming_content)
|
||||
self.assertEqual(content, b'This is the content of the file')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_custom_function_action_no_perm_response(self):
|
||||
"""Tests a custom action that returns an HttpResponse with 403 code."""
|
||||
action_data = {
|
||||
ACTION_CHECKBOX_NAME: [1],
|
||||
'action': 'no_perm',
|
||||
'index': 0,
|
||||
}
|
||||
response = self.client.post('/test_admin/admin/admin_views/externalsubscriber/', action_data)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.content, b'No permission to perform this action')
|
||||
|
||||
def test_actions_ordering(self):
|
||||
"""
|
||||
Ensure that actions are ordered as expected.
|
||||
@ -2440,9 +2463,13 @@ class AdminActionsTest(TestCase):
|
||||
response = self.client.get('/test_admin/admin/admin_views/externalsubscriber/')
|
||||
self.assertContains(response, '''<label>Action: <select name="action">
|
||||
<option value="" selected="selected">---------</option>
|
||||
<option value="delete_selected">Delete selected external subscribers</option>
|
||||
<option value="delete_selected">Delete selected external
|
||||
subscribers</option>
|
||||
<option value="redirect_to">Redirect to (Awesome action)</option>
|
||||
<option value="external_mail">External mail (Another awesome action)</option>
|
||||
<option value="external_mail">External mail (Another awesome
|
||||
action)</option>
|
||||
<option value="download">Download subscription</option>
|
||||
<option value="no_perm">No permission to run</option>
|
||||
</select>''', html=True)
|
||||
|
||||
def test_model_without_action(self):
|
||||
|
Loading…
Reference in New Issue
Block a user