Posted upstream as encode/django-rest-framework#10024. This copy stays here as the working draft; the discussion is the live conversation. The implementation it refers to is #2 on this fork.
References
Yes, DRF is feature-complete - here's why I think this still belongs here
RFC 10008 defines QUERY: safe and idempotent like GET, but carrying a request body like POST. It is the first new HTTP method since PATCH, and it targets a case DRF users hit constantly, a search or filter whose parameters are too large or too structured for a query string, currently expressed as a POST that lies about modifying state.
Both existing options fail, in opposite directions.
GET
Puts the filters in the request line, the most tightly bounded part of an HTTP request. Gunicorn caps it at 4094 bytes by default, Apache at 8190, nginx at the header buffer size, and CDNs, WAFs and corporate proxies each impose their own.
I've run into this directly: the filters outgrew the limit, and the fix was an infrastructure setting rather than an application change. That setting then has to be maintained, and a limit raised once is easily lost to an unrelated infrastructure change later.
POST
Removes the size problem by moving the filters into the body, and pays for it semantically. The request now advertises a state change that never happens, so the response is not cacheable, the request is not safely retryable, it needs a CSRF token on what is a read, and any permission class that branches on safety sees a write.
QUERY
The combination that was missing. Filters travel in the body, so the ceiling is one you control rather than the tightest limit on the path, and the request stays safe and idempotent, so caching, retries and read-only permission checks all behave correctly. That ceiling is already DRF's concern rather than purely Django's: #10013, merged in August 2026, enforces DATA_UPLOAD_MAX_MEMORY_SIZE on request.data parsing.
CONTRIBUTING.md says DRF is "essentially feature-complete" and "would prefer not to accept new features". Taken as a feature request, this should be closed, and I think that's the right outcome today.
The reason I'm raising it anyway is that the same document carves out changes "required for security reasons or to maintain compatibility with upcoming Django or Python versions". Django has accepted and assigned Trac #37232. Once that patch lands, DRF support stops being a new feature and becomes Django compatibility, the same category the compat.py PATCH shim has sat in for years. So the question isn't whether DRF wants a feature; it's what DRF does when the Django release underneath it grows a method it doesn't know about.
The proposal is to hold, not to merge: wait for Django, then revisit. Waiting is also what makes the change mergeable at all, since it lets DRF align with Django's real semantics (HttpRequest.body, the CSRF decision) rather than my guesses about them.
What the change actually looks like
I've written it to find out how big it is, so this can be a discussion about design rather than feasibility. Branch: query-method-support.
40 insertions of source across 8 files. The rest is 407 lines of tests (30 new) and docs across views.md, viewsets.md, routers.md, permissions.md, requests.md and testing.md.
It's that small because DRF's dispatch is already generic over the method: no hardcoded verb lists in views.py or viewsets.py, and request.py parses on content_type, so request.data already handles a QUERY body today with no change at all. Existing viewsets are unaffected, since get_method_map() only binds actions that exist.
The one line that isn't mechanical is adding QUERY to SAFE_METHODS. Correct per the RFC, but it changes IsAuthenticatedOrReadOnly and friends, and it rests on handler authors keeping the promise that a QUERY handler never writes. That is the piece I'd most want a maintainer's read on, and another reason to let Django decide the semantics first.
Where I'd like this to go
Entirely happy to take feedback, rework the approach, or park it until Django's patch lands. Equally happy for it to be closed if QUERY support isn't something DRF wants to carry, in which case most of those 40 lines are patchable from outside and it can live as a third-party shim instead. Mainly I'd rather the question was on record before Django ships than after.
References
http.HTTPMethod.QUERYYes, DRF is feature-complete - here's why I think this still belongs here
RFC 10008 defines
QUERY: safe and idempotent likeGET, but carrying a request body likePOST. It is the first new HTTP method sincePATCH, and it targets a case DRF users hit constantly, a search or filter whose parameters are too large or too structured for a query string, currently expressed as aPOSTthat lies about modifying state.Both existing options fail, in opposite directions.
GETPuts the filters in the request line, the most tightly bounded part of an HTTP request. Gunicorn caps it at 4094 bytes by default, Apache at 8190, nginx at the header buffer size, and CDNs, WAFs and corporate proxies each impose their own.
I've run into this directly: the filters outgrew the limit, and the fix was an infrastructure setting rather than an application change. That setting then has to be maintained, and a limit raised once is easily lost to an unrelated infrastructure change later.
POSTRemoves the size problem by moving the filters into the body, and pays for it semantically. The request now advertises a state change that never happens, so the response is not cacheable, the request is not safely retryable, it needs a CSRF token on what is a read, and any permission class that branches on safety sees a write.
QUERYThe combination that was missing. Filters travel in the body, so the ceiling is one you control rather than the tightest limit on the path, and the request stays safe and idempotent, so caching, retries and read-only permission checks all behave correctly. That ceiling is already DRF's concern rather than purely Django's: #10013, merged in August 2026, enforces
DATA_UPLOAD_MAX_MEMORY_SIZEonrequest.dataparsing.CONTRIBUTING.mdsays DRF is "essentially feature-complete" and "would prefer not to accept new features". Taken as a feature request, this should be closed, and I think that's the right outcome today.The reason I'm raising it anyway is that the same document carves out changes "required for security reasons or to maintain compatibility with upcoming Django or Python versions". Django has accepted and assigned Trac #37232. Once that patch lands, DRF support stops being a new feature and becomes Django compatibility, the same category the
compat.pyPATCH shim has sat in for years. So the question isn't whether DRF wants a feature; it's what DRF does when the Django release underneath it grows a method it doesn't know about.The proposal is to hold, not to merge: wait for Django, then revisit. Waiting is also what makes the change mergeable at all, since it lets DRF align with Django's real semantics (
HttpRequest.body, the CSRF decision) rather than my guesses about them.What the change actually looks like
I've written it to find out how big it is, so this can be a discussion about design rather than feasibility. Branch:
query-method-support.40 insertions of source across 8 files. The rest is 407 lines of tests (30 new) and docs across
views.md,viewsets.md,routers.md,permissions.md,requests.mdandtesting.md.It's that small because DRF's dispatch is already generic over the method: no hardcoded verb lists in
views.pyorviewsets.py, andrequest.pyparses oncontent_type, sorequest.dataalready handles aQUERYbody today with no change at all. Existing viewsets are unaffected, sinceget_method_map()only binds actions that exist.The one line that isn't mechanical is adding
QUERYtoSAFE_METHODS. Correct per the RFC, but it changesIsAuthenticatedOrReadOnlyand friends, and it rests on handler authors keeping the promise that aQUERYhandler never writes. That is the piece I'd most want a maintainer's read on, and another reason to let Django decide the semantics first.Where I'd like this to go
Entirely happy to take feedback, rework the approach, or park it until Django's patch lands. Equally happy for it to be closed if
QUERYsupport isn't something DRF wants to carry, in which case most of those 40 lines are patchable from outside and it can live as a third-party shim instead. Mainly I'd rather the question was on record before Django ships than after.