drf-query-method 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/dependabot.yml +5 -0
  2. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/workflows/ci.yml +2 -2
  3. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/workflows/codeql.yml +2 -2
  4. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/workflows/publish.yml +2 -2
  5. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/workflows/zizmor.yml +1 -1
  6. drf_query_method-0.3.0/CHANGELOG/0.3.0.md +11 -0
  7. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/PKG-INFO +15 -3
  8. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/README.md +14 -2
  9. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/docs/usage.md +17 -4
  10. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/pyproject.toml +1 -1
  11. drf_query_method-0.3.0/src/drf_query_method/methods.py +47 -0
  12. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/settings.py +7 -0
  13. drf_query_method-0.3.0/tests/test_csrf.py +39 -0
  14. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/urls.py +2 -1
  15. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/views.py +13 -0
  16. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/uv.lock +1 -1
  17. drf_query_method-0.2.0/src/drf_query_method/methods.py +0 -16
  18. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.editorconfig +0 -0
  19. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  20. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  21. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  22. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/pull_request_template.md +0 -0
  23. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.github/workflows/docs.yml +0 -0
  24. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/.gitignore +0 -0
  25. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/CHANGELOG/0.1.0.md +0 -0
  26. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/CHANGELOG/0.2.0.md +0 -0
  27. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/CHANGELOG/unreleased.md +0 -0
  28. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/CODE_OF_CONDUCT.md +0 -0
  29. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/CONTRIBUTING.md +0 -0
  30. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/LICENSE +0 -0
  31. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/SECURITY.md +0 -0
  32. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/docs/api.md +0 -0
  33. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/docs/index.md +0 -0
  34. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/docs/installation.md +0 -0
  35. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/justfile +0 -0
  36. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/scripts/release.py +0 -0
  37. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/__init__.py +0 -0
  38. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/django_filters.py +0 -0
  39. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/filters.py +0 -0
  40. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/params.py +0 -0
  41. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/patching.py +0 -0
  42. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/permissions.py +0 -0
  43. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/py.typed +0 -0
  44. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/routers.py +0 -0
  45. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/test.py +0 -0
  46. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/src/drf_query_method/viewsets.py +0 -0
  47. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/__init__.py +0 -0
  48. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/conftest.py +0 -0
  49. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_datatables.py +0 -0
  50. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_django_filters.py +0 -0
  51. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_drf_query_method.py +0 -0
  52. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_filters.py +0 -0
  53. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_methods.py +0 -0
  54. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_params.py +0 -0
  55. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_patching.py +0 -0
  56. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_permissions.py +0 -0
  57. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_routers.py +0 -0
  58. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/tests/test_test.py +0 -0
  59. {drf_query_method-0.2.0 → drf_query_method-0.3.0}/zensical.toml +0 -0
@@ -6,6 +6,11 @@ updates:
6
6
  interval: weekly
7
7
  cooldown:
8
8
  default-days: 7
9
+ groups:
10
+ # CodeQL's init and analyze steps must run the same version.
11
+ codeql-action:
12
+ patterns:
13
+ - "github/codeql-action*"
9
14
  open-pull-requests-limit: 5
10
15
 
11
16
  - package-ecosystem: uv
@@ -122,7 +122,7 @@ jobs:
122
122
  - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
123
123
 
124
124
  - name: Download coverage data
125
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
125
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
126
126
  with:
127
127
  pattern: coverage-*
128
128
  merge-multiple: true
@@ -144,6 +144,6 @@ jobs:
144
144
  runs-on: ubuntu-latest
145
145
  steps:
146
146
  - name: Check job results
147
- uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
147
+ uses: re-actors/alls-green@b5b5b37504aa4183270bd3d855c52a67f212be35 # v1.3.0
148
148
  with:
149
149
  jobs: ${{ toJSON(needs) }}
@@ -25,11 +25,11 @@ jobs:
25
25
  persist-credentials: false
26
26
 
27
27
  - name: Initialize CodeQL
28
- uses: github/codeql-action/init@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
28
+ uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
29
29
  with:
30
30
  languages: python # Add c-cpp, go, java-kotlin, or swift if needed
31
31
  build-mode: none # Switch to autobuild for compiled languages
32
32
  queries: security-extended
33
33
 
34
34
  - name: Perform CodeQL Analysis
35
- uses: github/codeql-action/analyze@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
35
+ uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
@@ -50,13 +50,13 @@ jobs:
50
50
  url: https://pypi.org/p/drf-query-method
51
51
  steps:
52
52
  - name: Download distribution
53
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
53
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
54
54
  with:
55
55
  name: dist
56
56
  path: dist/
57
57
 
58
58
  - name: Attest build provenance
59
- uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
59
+ uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
60
60
  with:
61
61
  subject-path: "dist/*"
62
62
 
@@ -31,7 +31,7 @@ jobs:
31
31
  persist-credentials: false
32
32
 
33
33
  - name: Run zizmor
34
- uses: zizmorcore/zizmor-action@6fc4b006235f201fdab3722e17240ab420d580e5 # v0.6.1
34
+ uses: zizmorcore/zizmor-action@53290badfa369cb0bf7ad16342cb62c2fa47ac7b # v0.8.0
35
35
  with:
36
36
  advanced-security: ${{ github.event.repository.private == false || vars.CODE_SECURITY_ENABLED == 'true' }}
37
37
  inputs: ./.github/
@@ -0,0 +1,11 @@
1
+ # drf-query-method 0.3.0
2
+
3
+ ## Changed
4
+
5
+ - On Django 4.2 to 6.1, `add_query_method()` (and so `patch()`) now treats `QUERY` as a safe method in Django's
6
+ `CsrfViewMiddleware`, matching Django 6.2. `QUERY` requests no longer need a CSRF token on any supported version,
7
+ including session-authenticated requests through DRF's `SessionAuthentication`.
8
+
9
+ ## Documentation
10
+
11
+ - README and usage docs explain CSRF for `QUERY`, and the README no longer says the package is unreleased.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: drf-query-method
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: HTTP QUERY method (RFC 10008) support for Django REST framework.
5
5
  Project-URL: bugs, https://github.com/BenA-SA/drf-query-method/issues
6
6
  Project-URL: changelog, https://github.com/BenA-SA/drf-query-method/releases
@@ -78,12 +78,24 @@ Routers then send `QUERY /notes/` to `query()`, and `SearchFilter`, `OrderingFil
78
78
  classes with the same names from `drf_query_method` instead. See the [documentation](https://BenA-SA.github.io/drf-query-method/usage/)
79
79
  for both approaches, and for sending `QUERY` requests from JavaScript and other clients.
80
80
 
81
- The package is in early development and not yet released.
81
+ The package is in early development. Releases are on [PyPI](https://pypi.org/project/drf-query-method/).
82
+
83
+ ## CSRF
84
+
85
+ `QUERY` is a safe method, so it never needs a CSRF token, on any supported Django version. Django 6.2 exempts it from
86
+ CSRF checks itself. On Django 4.2 to 6.1, where this package adds `QUERY`, it also teaches Django's
87
+ `CsrfViewMiddleware` to treat `QUERY` as safe, so the behaviour matches 6.2. DRF's `SessionAuthentication` uses the same
88
+ check, so session-authenticated `QUERY` requests work without a token too.
89
+
90
+ The trade-off is the one `GET` has always had: a `query()` handler must never change data. Cross-site requests are
91
+ still guarded by CORS, because browsers can only send `QUERY` from JavaScript, and `QUERY` isn't a CORS-safelisted
92
+ method, so a cross-origin request needs your server's permission first.
82
93
 
83
94
  ## Compatibility
84
95
 
85
96
  * Python 3.10+
86
- * Django 4.2, 5.0, 5.1, 5.2, 6.0 and 6.1. Django 6.2 adds `QUERY` natively; on earlier versions this package adds it.
97
+ * Django 4.2, 5.0, 5.1, 5.2, 6.0 and 6.1. Django 6.2 adds `QUERY` natively; on earlier versions this package adds it,
98
+ including Django 6.2's CSRF behaviour.
87
99
  * Django REST framework 3.16+
88
100
  * django-filter and django-rest-framework-datatables, optionally
89
101
 
@@ -40,12 +40,24 @@ Routers then send `QUERY /notes/` to `query()`, and `SearchFilter`, `OrderingFil
40
40
  classes with the same names from `drf_query_method` instead. See the [documentation](https://BenA-SA.github.io/drf-query-method/usage/)
41
41
  for both approaches, and for sending `QUERY` requests from JavaScript and other clients.
42
42
 
43
- The package is in early development and not yet released.
43
+ The package is in early development. Releases are on [PyPI](https://pypi.org/project/drf-query-method/).
44
+
45
+ ## CSRF
46
+
47
+ `QUERY` is a safe method, so it never needs a CSRF token, on any supported Django version. Django 6.2 exempts it from
48
+ CSRF checks itself. On Django 4.2 to 6.1, where this package adds `QUERY`, it also teaches Django's
49
+ `CsrfViewMiddleware` to treat `QUERY` as safe, so the behaviour matches 6.2. DRF's `SessionAuthentication` uses the same
50
+ check, so session-authenticated `QUERY` requests work without a token too.
51
+
52
+ The trade-off is the one `GET` has always had: a `query()` handler must never change data. Cross-site requests are
53
+ still guarded by CORS, because browsers can only send `QUERY` from JavaScript, and `QUERY` isn't a CORS-safelisted
54
+ method, so a cross-origin request needs your server's permission first.
44
55
 
45
56
  ## Compatibility
46
57
 
47
58
  * Python 3.10+
48
- * Django 4.2, 5.0, 5.1, 5.2, 6.0 and 6.1. Django 6.2 adds `QUERY` natively; on earlier versions this package adds it.
59
+ * Django 4.2, 5.0, 5.1, 5.2, 6.0 and 6.1. Django 6.2 adds `QUERY` natively; on earlier versions this package adds it,
60
+ including Django 6.2's CSRF behaviour.
49
61
  * Django REST framework 3.16+
50
62
  * django-filter and django-rest-framework-datatables, optionally
51
63
 
@@ -135,8 +135,8 @@ A few things to check before relying on `QUERY` in production:
135
135
  CORS_ALLOW_METHODS = (*default_methods, "QUERY")
136
136
  ```
137
137
 
138
- * **CSRF.** On Django versions before 6.2, session-authenticated `QUERY` requests need a CSRF token, the same as
139
- `POST`.
138
+ * **CSRF.** None needed: `QUERY` is a safe method, so it never needs a CSRF token on any supported Django version. See
139
+ [Django versions before 6.2](#django-versions-before-62) for how older versions get the same behaviour.
140
140
  * **Proxies, CDNs and firewalls.** Some reject request methods they don't recognise. Check that `QUERY` reaches your
141
141
  application through everything in front of it.
142
142
  * **Caching.** `QUERY` responses are cacheable in principle, but caches generally don't key on request bodies, and
@@ -161,8 +161,21 @@ still read from the URL.
161
161
 
162
162
  ## Django versions before 6.2
163
163
 
164
- Django 6.2 supports `QUERY` natively. On earlier versions this package adds it, with one difference: Django's CSRF
165
- middleware treats `QUERY` as unsafe until 6.2, so session-authenticated `QUERY` requests need a CSRF token.
164
+ Django 6.2 supports `QUERY` natively. On Django 4.2 to 6.1, `add_query_method()` (which `patch()` calls) brings the same
165
+ behaviour to older versions in two ways:
166
+
167
+ * It adds `query` to Django's allowed view methods, so views can define a `query()` handler.
168
+ * It treats `QUERY` as a safe method in `CsrfViewMiddleware`, as Django 6.2 does. Before 6.2 the middleware only
169
+ exempts `GET`, `HEAD`, `OPTIONS` and `TRACE`, so without this, session-authenticated `QUERY` requests would need a
170
+ CSRF token. DRF's `SessionAuthentication` checks CSRF through the same middleware, so it follows suit.
171
+
172
+ The result is that `QUERY` never needs a CSRF token, whichever supported Django version you're on. If you call
173
+ `add_query_method()` yourself rather than `patch()`, call it once at startup, before requests are served.
174
+
175
+ This is safe for the same reason it is in Django 6.2. CSRF protects against another site making a logged-in user's
176
+ browser send a request. HTML forms can only send `GET` and `POST`, so `QUERY` can only come from JavaScript, and
177
+ because `QUERY` is not a CORS-safelisted method, the browser asks your server's permission with a preflight request
178
+ before sending a cross-origin one. As with `GET`, a `query()` handler must never change data.
166
179
 
167
180
  ## Moving to DRF's own support
168
181
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "drf-query-method"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "HTTP QUERY method (RFC 10008) support for Django REST framework."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -0,0 +1,47 @@
1
+ """Make Django accept the QUERY method on versions before 6.2."""
2
+
3
+ import functools
4
+
5
+ from django.middleware.csrf import CsrfViewMiddleware
6
+ from django.views.generic import View
7
+
8
+
9
+ def add_query_method() -> None:
10
+ """Make Django before 6.2 handle ``QUERY`` as Django 6.2 does.
11
+
12
+ Django 6.2 supports ``QUERY`` natively, so this does nothing there. On
13
+ earlier versions it adds ``query`` to ``View.http_method_names``, so any
14
+ view, including DRF's, can dispatch ``QUERY`` requests to a ``query()``
15
+ handler, and it treats ``QUERY`` as a safe method in
16
+ ``CsrfViewMiddleware``, so ``QUERY`` requests need no CSRF token. See
17
+ :func:`skip_csrf_for_query`.
18
+ """
19
+ if "query" in View.http_method_names:
20
+ return
21
+ View.http_method_names = [*View.http_method_names, "query"]
22
+ CsrfViewMiddleware.process_view = skip_csrf_for_query(CsrfViewMiddleware.process_view)
23
+
24
+
25
+ def skip_csrf_for_query(process_view):
26
+ """Wrap ``CsrfViewMiddleware.process_view`` to accept ``QUERY`` like ``GET``.
27
+
28
+ Django 6.2 adds ``QUERY`` to the methods the middleware exempts as safe
29
+ under RFC 9110. Earlier versions hard-code ``GET``, ``HEAD``, ``OPTIONS``
30
+ and ``TRACE``, so the wrapper sends ``QUERY`` down the same path: a request
31
+ already processed, or a ``csrf_exempt`` view, is left alone, and anything
32
+ else is accepted without a token. Every other method falls through to
33
+ Django unchanged.
34
+
35
+ DRF's ``SessionAuthentication`` checks CSRF through ``CSRFCheck``, a
36
+ ``CsrfViewMiddleware`` subclass, so it follows the same rule.
37
+ """
38
+
39
+ @functools.wraps(process_view)
40
+ def wrapper(self, request, callback, callback_args, callback_kwargs):
41
+ if request.method != "QUERY":
42
+ return process_view(self, request, callback, callback_args, callback_kwargs)
43
+ if getattr(request, "csrf_processing_done", False) or getattr(callback, "csrf_exempt", False):
44
+ return None
45
+ return self._accept(request)
46
+
47
+ return wrapper
@@ -5,12 +5,19 @@ SECRET_KEY = "drf-query-method-tests"
5
5
  INSTALLED_APPS = [
6
6
  "django.contrib.auth",
7
7
  "django.contrib.contenttypes",
8
+ "django.contrib.sessions",
8
9
  "django_filters",
9
10
  "rest_framework",
10
11
  ]
11
12
 
12
13
  ROOT_URLCONF = "tests.urls"
13
14
 
15
+ MIDDLEWARE = [
16
+ "django.contrib.sessions.middleware.SessionMiddleware",
17
+ "django.middleware.csrf.CsrfViewMiddleware",
18
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
19
+ ]
20
+
14
21
  DATABASES = {
15
22
  "default": {
16
23
  "ENGINE": "django.db.backends.sqlite3",
@@ -0,0 +1,39 @@
1
+ import pytest
2
+ from django.contrib.auth.models import User
3
+ from django.http import HttpResponse
4
+ from django.middleware.csrf import CsrfViewMiddleware
5
+ from django.test import RequestFactory
6
+
7
+ from drf_query_method import add_query_method
8
+ from drf_query_method.test import APIClient
9
+
10
+
11
+ @pytest.fixture
12
+ def client(db):
13
+ client = APIClient(enforce_csrf_checks=True)
14
+ client.force_login(User.objects.create(username="alice"))
15
+ return client
16
+
17
+
18
+ def test_session_authenticated_query_needs_no_csrf_token(client):
19
+ response = client.query("/session/", {"search": "a"}, format="json")
20
+ assert response.status_code == 200
21
+ assert response.data == {"method": "QUERY"}
22
+
23
+
24
+ def test_session_authenticated_post_still_needs_a_csrf_token(client):
25
+ assert client.post("/session/", {}, format="json").status_code == 403
26
+
27
+
28
+ def test_csrf_middleware_accepts_query_as_a_safe_method():
29
+ middleware = CsrfViewMiddleware(lambda request: HttpResponse())
30
+ request = RequestFactory().generic("QUERY", "/")
31
+ assert middleware.process_view(request, lambda request: HttpResponse(), (), {}) is None
32
+ assert request.csrf_processing_done
33
+
34
+
35
+ def test_add_query_method_wraps_the_middleware_once():
36
+ add_query_method()
37
+ add_query_method()
38
+ process_view = CsrfViewMiddleware.process_view
39
+ assert not hasattr(getattr(process_view, "__wrapped__", None), "__wrapped__")
@@ -1,8 +1,9 @@
1
1
  from django.urls import path
2
2
 
3
- from tests.views import QueryEchoView, redirect_view
3
+ from tests.views import QueryEchoView, SessionQueryView, redirect_view
4
4
 
5
5
  urlpatterns = [
6
6
  path("query/", QueryEchoView.as_view()),
7
7
  path("redirect/", redirect_view),
8
+ path("session/", SessionQueryView.as_view()),
8
9
  ]
@@ -3,7 +3,9 @@
3
3
  from django.contrib.auth.models import User
4
4
  from django.http.response import HttpResponseRedirectBase
5
5
  from rest_framework import generics, serializers
6
+ from rest_framework.authentication import SessionAuthentication
6
7
  from rest_framework.decorators import action, api_view
8
+ from rest_framework.permissions import IsAuthenticated
7
9
  from rest_framework.response import Response
8
10
  from rest_framework.views import APIView
9
11
 
@@ -72,3 +74,14 @@ class QueryActionViewSet(viewsets.GenericViewSet):
72
74
  @action(detail=False, methods=["post"])
73
75
  def query(self, request):
74
76
  return Response("action")
77
+
78
+
79
+ class SessionQueryView(APIView):
80
+ authentication_classes = [SessionAuthentication]
81
+ permission_classes = [IsAuthenticated]
82
+
83
+ def query(self, request):
84
+ return Response({"method": request.method})
85
+
86
+ def post(self, request):
87
+ return Response({"method": request.method})
@@ -422,7 +422,7 @@ wheels = [
422
422
 
423
423
  [[package]]
424
424
  name = "drf-query-method"
425
- version = "0.2.0"
425
+ version = "0.3.0"
426
426
  source = { editable = "." }
427
427
  dependencies = [
428
428
  { name = "django", version = "5.2.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
@@ -1,16 +0,0 @@
1
- """Make Django accept the QUERY method on versions before 6.2."""
2
-
3
- from django.views.generic import View
4
-
5
-
6
- def add_query_method() -> None:
7
- """Add ``query`` to Django's ``View.http_method_names`` if it is missing.
8
-
9
- Django 6.2 lists ``query`` itself, so this does nothing there. On earlier
10
- versions it lets any view, including DRF's, dispatch ``QUERY`` requests to
11
- a ``query()`` handler. Earlier versions of Django's CSRF middleware treat
12
- ``QUERY`` as unsafe, so session-authenticated ``QUERY`` requests need a
13
- CSRF token until Django 6.2.
14
- """
15
- if "query" not in View.http_method_names:
16
- View.http_method_names = [*View.http_method_names, "query"]