Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
b27db97b
Kaydet (Commit)
b27db97b
authored
Ara 20, 2014
tarafından
Thomas Tanner
Kaydeden (comit)
Tim Graham
Ara 24, 2014
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #22461 -- Added if-unmodified-since support to the condition decorator.
üst
fae551d7
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
111 additions
and
32 deletions
+111
-32
http.py
django/views/decorators/http.py
+35
-29
1.8.txt
docs/releases/1.8.txt
+3
-0
conditional-view-processing.txt
docs/topics/conditional-view-processing.txt
+13
-3
tests.py
tests/conditional_processing/tests.py
+60
-0
No files found.
django/views/decorators/http.py
Dosyayı görüntüle @
b27db97b
...
@@ -52,6 +52,16 @@ require_safe = require_http_methods(["GET", "HEAD"])
...
@@ -52,6 +52,16 @@ require_safe = require_http_methods(["GET", "HEAD"])
require_safe
.
__doc__
=
"Decorator to require that a view only accept safe methods: GET and HEAD."
require_safe
.
__doc__
=
"Decorator to require that a view only accept safe methods: GET and HEAD."
def
_precondition_failed
(
request
):
logger
.
warning
(
'Precondition Failed:
%
s'
,
request
.
path
,
extra
=
{
'status_code'
:
412
,
'request'
:
request
},
)
return
HttpResponse
(
status
=
412
)
def
condition
(
etag_func
=
None
,
last_modified_func
=
None
):
def
condition
(
etag_func
=
None
,
last_modified_func
=
None
):
"""
"""
Decorator to support conditional retrieval (or change) for a view
Decorator to support conditional retrieval (or change) for a view
...
@@ -81,8 +91,12 @@ def condition(etag_func=None, last_modified_func=None):
...
@@ -81,8 +91,12 @@ def condition(etag_func=None, last_modified_func=None):
if_modified_since
=
request
.
META
.
get
(
"HTTP_IF_MODIFIED_SINCE"
)
if_modified_since
=
request
.
META
.
get
(
"HTTP_IF_MODIFIED_SINCE"
)
if
if_modified_since
:
if
if_modified_since
:
if_modified_since
=
parse_http_date_safe
(
if_modified_since
)
if_modified_since
=
parse_http_date_safe
(
if_modified_since
)
if_unmodified_since
=
request
.
META
.
get
(
"HTTP_IF_UNMODIFIED_SINCE"
)
if
if_unmodified_since
:
if_unmodified_since
=
parse_http_date_safe
(
if_unmodified_since
)
if_none_match
=
request
.
META
.
get
(
"HTTP_IF_NONE_MATCH"
)
if_none_match
=
request
.
META
.
get
(
"HTTP_IF_NONE_MATCH"
)
if_match
=
request
.
META
.
get
(
"HTTP_IF_MATCH"
)
if_match
=
request
.
META
.
get
(
"HTTP_IF_MATCH"
)
etags
=
[]
if
if_none_match
or
if_match
:
if
if_none_match
or
if_match
:
# There can be more than one ETag in the request, so we
# There can be more than one ETag in the request, so we
# consider the list of values.
# consider the list of values.
...
@@ -97,21 +111,19 @@ def condition(etag_func=None, last_modified_func=None):
...
@@ -97,21 +111,19 @@ def condition(etag_func=None, last_modified_func=None):
if_match
=
None
if_match
=
None
# Compute values (if any) for the requested resource.
# Compute values (if any) for the requested resource.
if
etag_func
:
def
get_last_modified
():
res_etag
=
etag_func
(
request
,
*
args
,
**
kwargs
)
if
last_modified_func
:
else
:
dt
=
last_modified_func
(
request
,
*
args
,
**
kwargs
)
res_etag
=
None
if
dt
:
if
last_modified_func
:
return
timegm
(
dt
.
utctimetuple
())
dt
=
last_modified_func
(
request
,
*
args
,
**
kwargs
)
if
dt
:
res_etag
=
etag_func
(
request
,
*
args
,
**
kwargs
)
if
etag_func
else
None
res_last_modified
=
timegm
(
dt
.
utctimetuple
())
res_last_modified
=
get_last_modified
()
else
:
res_last_modified
=
None
else
:
res_last_modified
=
None
response
=
None
response
=
None
if
not
((
if_match
and
(
if_modified_since
or
if_none_match
))
or
if
not
((
if_match
and
if_modified_since
)
or
(
if_none_match
and
if_unmodified_since
)
or
(
if_modified_since
and
if_unmodified_since
)
or
(
if_match
and
if_none_match
)):
(
if_match
and
if_none_match
)):
# We only get here if no undefined combinations of headers are
# We only get here if no undefined combinations of headers are
# specified.
# specified.
...
@@ -123,26 +135,20 @@ def condition(etag_func=None, last_modified_func=None):
...
@@ -123,26 +135,20 @@ def condition(etag_func=None, last_modified_func=None):
if
request
.
method
in
(
"GET"
,
"HEAD"
):
if
request
.
method
in
(
"GET"
,
"HEAD"
):
response
=
HttpResponseNotModified
()
response
=
HttpResponseNotModified
()
else
:
else
:
logger
.
warning
(
'Precondition Failed:
%
s'
,
request
.
path
,
response
=
_precondition_failed
(
request
)
extra
=
{
elif
(
if_match
and
((
not
res_etag
and
"*"
in
etags
)
or
'status_code'
:
412
,
(
res_etag
and
res_etag
not
in
etags
)
or
'request'
:
request
(
res_last_modified
and
if_unmodified_since
and
}
res_last_modified
>
if_unmodified_since
))):
)
response
=
_precondition_failed
(
request
)
response
=
HttpResponse
(
status
=
412
)
elif
if_match
and
((
not
res_etag
and
"*"
in
etags
)
or
(
res_etag
and
res_etag
not
in
etags
)):
logger
.
warning
(
'Precondition Failed:
%
s'
,
request
.
path
,
extra
=
{
'status_code'
:
412
,
'request'
:
request
}
)
response
=
HttpResponse
(
status
=
412
)
elif
(
not
if_none_match
and
request
.
method
in
(
"GET"
,
"HEAD"
)
and
elif
(
not
if_none_match
and
request
.
method
in
(
"GET"
,
"HEAD"
)
and
res_last_modified
and
if_modified_since
and
res_last_modified
and
if_modified_since
and
res_last_modified
<=
if_modified_since
):
res_last_modified
<=
if_modified_since
):
response
=
HttpResponseNotModified
()
response
=
HttpResponseNotModified
()
elif
(
not
if_match
and
res_last_modified
and
if_unmodified_since
and
res_last_modified
>
if_unmodified_since
):
response
=
_precondition_failed
(
request
)
if
response
is
None
:
if
response
is
None
:
response
=
func
(
request
,
*
args
,
**
kwargs
)
response
=
func
(
request
,
*
args
,
**
kwargs
)
...
...
docs/releases/1.8.txt
Dosyayı görüntüle @
b27db97b
...
@@ -528,6 +528,9 @@ Requests and Responses
...
@@ -528,6 +528,9 @@ Requests and Responses
<django.http.HttpResponse.setdefault>` method allows setting a header unless
<django.http.HttpResponse.setdefault>` method allows setting a header unless
it has already been set.
it has already been set.
* The :func:`~django.views.decorators.http.condition` decorator for
conditional view processing now supports the ``If-unmodified-since`` header.
Tests
Tests
^^^^^
^^^^^
...
...
docs/topics/conditional-view-processing.txt
Dosyayı görüntüle @
b27db97b
...
@@ -15,18 +15,29 @@ or you can rely on the :class:`~django.middleware.common.CommonMiddleware`
...
@@ -15,18 +15,29 @@ or you can rely on the :class:`~django.middleware.common.CommonMiddleware`
middleware to set the ``ETag`` header.
middleware to set the ``ETag`` header.
When the client next requests the same resource, it might send along a header
When the client next requests the same resource, it might send along a header
such as `If-modified-since`_, containing the date of the last modification
such as either `If-modified-since`_ or `If-unmodified-since`_, containing the
time it was sent, or `If-none-match`_, containing the ``ETag`` it was sent.
date of the last modification time it was sent, or either `If-match`_ or
`If-none-match`_, containing the last ``ETag`` it was sent.
If the current version of the page matches the ``ETag`` sent by the client, or
If the current version of the page matches the ``ETag`` sent by the client, or
if the resource has not been modified, a 304 status code can be sent back,
if the resource has not been modified, a 304 status code can be sent back,
instead of a full response, telling the client that nothing has changed.
instead of a full response, telling the client that nothing has changed.
Depending on the header, if the page has been modified or does not match the
``ETag`` sent by the client, a 412 status code (Precondition Failed) may be
returned.
.. _If-match: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24
.. _If-none-match: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
.. _If-none-match: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
.. _If-modified-since: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
.. _If-modified-since: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
.. _If-unmodified-since: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28
When you need more fine-grained control you may use per-view conditional
When you need more fine-grained control you may use per-view conditional
processing functions.
processing functions.
.. versionchanged:: 1.8
Support for the ``If-unmodified-since`` header was added to conditional
view processing.
.. _conditional-decorators:
.. _conditional-decorators:
The ``condition`` decorator
The ``condition`` decorator
...
@@ -194,4 +205,3 @@ view takes a while to generate the content, you should consider using the
...
@@ -194,4 +205,3 @@ view takes a while to generate the content, you should consider using the
fairly quickly, stick to using the middleware and the amount of network
fairly quickly, stick to using the middleware and the amount of network
traffic sent back to the clients will still be reduced if the view hasn't
traffic sent back to the clients will still be reduced if the view hasn't
changed.
changed.
tests/conditional_processing/tests.py
Dosyayı görüntüle @
b27db97b
...
@@ -49,6 +49,20 @@ class ConditionalGet(TestCase):
...
@@ -49,6 +49,20 @@ class ConditionalGet(TestCase):
response
=
self
.
client
.
get
(
'/condition/'
)
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
self
.
assertFullResponse
(
response
)
def
test_if_unmodified_since
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
LAST_MODIFIED_NEWER_STR
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
LAST_MODIFIED_INVALID_STR
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
EXPIRED_LAST_MODIFIED_STR
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertEqual
(
response
.
status_code
,
412
)
def
test_if_none_match
(
self
):
def
test_if_none_match
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_NONE_MATCH'
]
=
'"
%
s"'
%
ETAG
self
.
client
.
defaults
[
'HTTP_IF_NONE_MATCH'
]
=
'"
%
s"'
%
ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
response
=
self
.
client
.
get
(
'/condition/'
)
...
@@ -71,6 +85,7 @@ class ConditionalGet(TestCase):
...
@@ -71,6 +85,7 @@ class ConditionalGet(TestCase):
self
.
assertEqual
(
response
.
status_code
,
412
)
self
.
assertEqual
(
response
.
status_code
,
412
)
def
test_both_headers
(
self
):
def
test_both_headers
(
self
):
# see http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.4
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_NONE_MATCH'
]
=
'"
%
s"'
%
ETAG
self
.
client
.
defaults
[
'HTTP_IF_NONE_MATCH'
]
=
'"
%
s"'
%
ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
response
=
self
.
client
.
get
(
'/condition/'
)
...
@@ -86,6 +101,32 @@ class ConditionalGet(TestCase):
...
@@ -86,6 +101,32 @@ class ConditionalGet(TestCase):
response
=
self
.
client
.
get
(
'/condition/'
)
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
self
.
assertFullResponse
(
response
)
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
EXPIRED_LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_NONE_MATCH'
]
=
'"
%
s"'
%
EXPIRED_ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
def
test_both_headers_2
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MATCH'
]
=
'"
%
s"'
%
ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertFullResponse
(
response
)
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
EXPIRED_LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MATCH'
]
=
'"
%
s"'
%
EXPIRED_ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertEqual
(
response
.
status_code
,
412
)
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MATCH'
]
=
'"
%
s"'
%
EXPIRED_ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertEqual
(
response
.
status_code
,
412
)
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
EXPIRED_LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MATCH'
]
=
'"
%
s"'
%
ETAG
response
=
self
.
client
.
get
(
'/condition/'
)
self
.
assertEqual
(
response
.
status_code
,
412
)
def
test_single_condition_1
(
self
):
def
test_single_condition_1
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
response
=
self
.
client
.
get
(
'/condition/last_modified/'
)
response
=
self
.
client
.
get
(
'/condition/last_modified/'
)
...
@@ -124,6 +165,25 @@ class ConditionalGet(TestCase):
...
@@ -124,6 +165,25 @@ class ConditionalGet(TestCase):
response
=
self
.
client
.
get
(
'/condition/last_modified2/'
)
response
=
self
.
client
.
get
(
'/condition/last_modified2/'
)
self
.
assertFullResponse
(
response
,
check_etag
=
False
)
self
.
assertFullResponse
(
response
,
check_etag
=
False
)
def
test_single_condition_7
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
EXPIRED_LAST_MODIFIED_STR
response
=
self
.
client
.
get
(
'/condition/last_modified/'
)
self
.
assertEqual
(
response
.
status_code
,
412
)
response
=
self
.
client
.
get
(
'/condition/etag/'
)
self
.
assertFullResponse
(
response
,
check_last_modified
=
False
)
def
test_single_condition_8
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
response
=
self
.
client
.
get
(
'/condition/last_modified/'
)
self
.
assertFullResponse
(
response
,
check_etag
=
False
)
def
test_single_condition_9
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_UNMODIFIED_SINCE'
]
=
EXPIRED_LAST_MODIFIED_STR
response
=
self
.
client
.
get
(
'/condition/last_modified2/'
)
self
.
assertEqual
(
response
.
status_code
,
412
)
response
=
self
.
client
.
get
(
'/condition/etag2/'
)
self
.
assertFullResponse
(
response
,
check_last_modified
=
False
)
def
test_single_condition_head
(
self
):
def
test_single_condition_head
(
self
):
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
self
.
client
.
defaults
[
'HTTP_IF_MODIFIED_SINCE'
]
=
LAST_MODIFIED_STR
response
=
self
.
client
.
head
(
'/condition/'
)
response
=
self
.
client
.
head
(
'/condition/'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment