Skip to content

Commit 96c5fe6

Browse files
committed
add test coverage and example of a POST only tool
1 parent 37d56e1 commit 96c5fe6

File tree

5 files changed

+24
-9
lines changed

5 files changed

+24
-9
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,12 @@ preferable that actions use a HTTP POST instead of a GET.
186186
You can configure an action to only use POST with:
187187

188188
```python
189-
@action(methods=("post",), button_type="form")
189+
@action(methods=("POST",), button_type="form")
190190
```
191191

192-
One caveat is Django's styling is pinned to anchor tags[^1], so to maintain visual
193-
consistency with other actions, we have to use anchor tags too.
192+
One caveat is Django's styling is pinned to anchor tags[^1], so to maintain
193+
visual consistency with other actions, we have to use anchor tags too and use
194+
JavaScript to turn make it act like a form.
194195

195196
[^1]: https://github.com/django/django/blob/826ef006681eae1e9b4bd0e4f18fa13713025cba/django/contrib/admin/static/admin/css/base.css#L786
196197

@@ -267,4 +268,3 @@ open a simple form in a modal dialog.
267268

268269
If you want an actions menu for each row of your changelist, check out [Django
269270
Admin Row Actions](https://github.com/DjangoAdminHackers/django-admin-row-actions).
270-

django_object_actions/tests/test_admin.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,22 @@ def test_changelist_template_context(self):
7676
self.assertIn("foo", response.context_data)
7777

7878
def test_changelist_action_view(self):
79-
url = "/admin/polls/choice/actions/delete_all/"
79+
url = reverse("admin:polls_choice_actions", args=("delete_all",))
8080
response = self.client.get(url)
8181
self.assertRedirects(response, "/admin/polls/choice/")
8282

83+
def test_changelist_action_post_only_tool_rejects_get(self):
84+
poll = PollFactory.create()
85+
url = reverse(
86+
"admin:polls_choice_actions",
87+
args=(
88+
poll.pk,
89+
"reset_vote",
90+
),
91+
)
92+
response = self.client.get(url)
93+
self.assertEqual(response.status_code, 405)
94+
8395
def test_changelist_nonexistent_action(self):
8496
url = "/admin/polls/choice/actions/xyzzy/"
8597
response = self.client.get(url)

django_object_actions/tests/tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def test_can_return_template(self):
4646
# it's good to document that this is something we can do.
4747
url = reverse("admin:polls_poll_actions", args=(1, "delete_all_choices"))
4848
response = self.client.get(url)
49+
print(url, response)
4950
self.assertTemplateUsed(response, "clear_choices.html")
5051

5152
def test_message_user_sends_message(self):

django_object_actions/utils.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@ class BaseActionView(View):
218218
model = None
219219
actions = None
220220
current_app = None
221-
methods = ("GET", "POST")
222221

223222
@property
224223
def view_args(self):
@@ -250,8 +249,11 @@ def dispatch(self, request, tool, **kwargs):
250249
except KeyError:
251250
raise Http404("Action does not exist")
252251

253-
if request.method not in self.methods:
254-
return HttpResponseNotAllowed(view.methods)
252+
# TODO move ('get', 'post' config default someplace else)
253+
allowed_methods = getattr(view, "methods", ("GET", "POST"))
254+
print("dispatch", request.method, allowed_methods)
255+
if request.method.upper() not in allowed_methods:
256+
return HttpResponseNotAllowed(allowed_methods)
255257

256258
ret = view(request, *self.view_args)
257259
if isinstance(ret, HttpResponseBase):

example_project/polls/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def decrement_vote(self, request, obj):
4545
def delete_all(self, request, queryset):
4646
self.message_user(request, "just kidding!")
4747

48-
@action(description="0")
48+
@action(description="0", methods=("POST",), button_type="form")
4949
def reset_vote(self, request, obj):
5050
obj.votes = 0
5151
obj.save()

0 commit comments

Comments
 (0)