mirror of
https://github.com/django/django.git
synced 2025-08-03 10:34:04 +00:00
Fixed #35631 -- Added HttpRequest.get_preferred_type().
This commit is contained in:
parent
826ef00668
commit
e161bd4657
5 changed files with 247 additions and 26 deletions
|
@ -425,10 +425,48 @@ Methods
|
|||
Returns ``True`` if the request is secure; that is, if it was made with
|
||||
HTTPS.
|
||||
|
||||
.. method:: HttpRequest.get_preferred_type(media_types)
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
Returns the preferred mime type from ``media_types``, based on the
|
||||
``Accept`` header, or ``None`` if the client does not accept any of the
|
||||
provided types.
|
||||
|
||||
Assuming the client sends an ``Accept`` header of
|
||||
``text/html,application/json;q=0.8``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> request.get_preferred_type(["text/html", "application/json"])
|
||||
"text/html"
|
||||
>>> request.get_preferred_type(["application/json", "text/plain"])
|
||||
"application/json"
|
||||
>>> request.get_preferred_type(["application/xml", "text/plain"])
|
||||
None
|
||||
|
||||
Most browsers send ``Accept: */*`` by default, meaning they don't have a
|
||||
preference, in which case the first item in ``media_types`` would be
|
||||
returned.
|
||||
|
||||
Setting an explicit ``Accept`` header in API requests can be useful for
|
||||
returning a different content type for those consumers only. See
|
||||
:ref:`content-negotiation-example` for an example of returning
|
||||
different content based on the ``Accept`` header.
|
||||
|
||||
.. note::
|
||||
|
||||
If a response varies depending on the content of the ``Accept`` header
|
||||
and you are using some form of caching like Django's
|
||||
:mod:`cache middleware <django.middleware.cache>`, you should decorate
|
||||
the view with :func:`vary_on_headers('Accept')
|
||||
<django.views.decorators.vary.vary_on_headers>` so that the responses
|
||||
are properly cached.
|
||||
|
||||
.. method:: HttpRequest.accepts(mime_type)
|
||||
|
||||
Returns ``True`` if the request ``Accept`` header matches the ``mime_type``
|
||||
argument:
|
||||
Returns ``True`` if the request's ``Accept`` header matches the
|
||||
``mime_type`` argument:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
|
@ -436,17 +474,10 @@ Methods
|
|||
True
|
||||
|
||||
Most browsers send ``Accept: */*`` by default, so this would return
|
||||
``True`` for all content types. Setting an explicit ``Accept`` header in
|
||||
API requests can be useful for returning a different content type for those
|
||||
consumers only. See :ref:`content-negotiation-example` of using
|
||||
``accepts()`` to return different content to API consumers.
|
||||
``True`` for all content types.
|
||||
|
||||
If a response varies depending on the content of the ``Accept`` header and
|
||||
you are using some form of caching like Django's :mod:`cache middleware
|
||||
<django.middleware.cache>`, you should decorate the view with
|
||||
:func:`vary_on_headers('Accept')
|
||||
<django.views.decorators.vary.vary_on_headers>` so that the responses are
|
||||
properly cached.
|
||||
See :ref:`content-negotiation-example` for an example of using
|
||||
``accepts()`` to return different content based on the ``Accept`` header.
|
||||
|
||||
.. method:: HttpRequest.read(size=None)
|
||||
.. method:: HttpRequest.readline()
|
||||
|
|
|
@ -226,7 +226,8 @@ Models
|
|||
Requests and Responses
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* The new :meth:`.HttpRequest.get_preferred_type` method can be used to query
|
||||
the preferred media type the client accepts.
|
||||
|
||||
Security
|
||||
~~~~~~~~
|
||||
|
@ -309,6 +310,9 @@ Miscellaneous
|
|||
|
||||
* The minimum supported version of ``gettext`` is increased from 0.15 to 0.19.
|
||||
|
||||
* ``HttpRequest.accepted_types`` is now sorted by the client's preference, based
|
||||
on the request's ``Accept`` header.
|
||||
|
||||
.. _deprecated-features-5.2:
|
||||
|
||||
Features deprecated in 5.2
|
||||
|
|
|
@ -273,3 +273,56 @@ works with an API-based workflow as well as 'normal' form POSTs::
|
|||
class AuthorCreateView(JsonableResponseMixin, CreateView):
|
||||
model = Author
|
||||
fields = ["name"]
|
||||
|
||||
The above example assumes that if the client supports ``text/html``, that they
|
||||
would prefer it. However, this may not always be true. When requesting a
|
||||
``.css`` file, many browsers will send the header
|
||||
``Accept: text/css,*/*;q=0.1``, indicating that they would prefer CSS, but
|
||||
anything else is fine. This means ``request.accepts("text/html") will be
|
||||
``True``.
|
||||
|
||||
To determine the correct format, taking into consideration the client's
|
||||
preference, use :func:`django.http.HttpRequest.get_preferred_type`::
|
||||
|
||||
class JsonableResponseMixin:
|
||||
"""
|
||||
Mixin to add JSON support to a form.
|
||||
Must be used with an object-based FormView (e.g. CreateView).
|
||||
"""
|
||||
|
||||
accepted_media_types = ["text/html", "application/json"]
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.get_preferred_type(self.accepted_media_types) is None:
|
||||
# No format in common.
|
||||
return HttpResponse(
|
||||
status_code=406, headers={"Accept": ",".join(self.accepted_media_types)}
|
||||
)
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_invalid(self, form):
|
||||
response = super().form_invalid(form)
|
||||
accepted_type = request.get_preferred_type(self.accepted_media_types)
|
||||
if accepted_type == "text/html":
|
||||
return response
|
||||
elif accepted_type == "application/json":
|
||||
return JsonResponse(form.errors, status=400)
|
||||
|
||||
def form_valid(self, form):
|
||||
# We make sure to call the parent's form_valid() method because
|
||||
# it might do some processing (in the case of CreateView, it will
|
||||
# call form.save() for example).
|
||||
response = super().form_valid(form)
|
||||
accepted_type = request.get_preferred_type(self.accepted_media_types)
|
||||
if accepted_type == "text/html":
|
||||
return response
|
||||
elif accepted_type == "application/json":
|
||||
data = {
|
||||
"pk": self.object.pk,
|
||||
}
|
||||
return JsonResponse(data)
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
The :meth:`.HttpRequest.get_preferred_type` method was added.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue