On demand content processing
HTTP clients may send protocol headers to tell the server which resources they have seen. This is when getting the web page (using HTTP)
GETRequest) is very common to avoid sending the complete data already obtained by the client. However, the same protocol header can be used for all HTTP methods（
DELETE, and others).
For each page (response) sent back by Django from the view, two HTTP protocol headers are provided:
Last-Modified. These protocol headers are optional in the HTTP response. They can be set by your view functions, or you can rely on them
When your client requests the same resource again, it may sendIf-modified-sinceperhapsIf-unmodified-sinceThe protocol header containing the last modification time previously sent; orIf-matchorIf-none-matchProtocol header, containing the previously sent
ETag. If the current version of the page matches the
ETagOr if the resource has not been modified, a 304 status code will be sent back instead of a complete reply to tell the client that there is no modification. According to the protocol header, if the page is modified or does not match the message sent by the client
ETag, 412 (precondition failed) status code will be returned.
When you need more refined control, you can use the on-demand processing function of each view.
Changed in Django 1.8:
Add to on demand view processing
If-unmodified-sinceSupport of protocol header
Sometimes (actually often), you can create functions to quickly calculate the cost of resourcesETagValue or last modified time,notYou need to perform all the steps required to build a full view. Django can use these functions to provide an “early bailout” option for view processing. To tell the client that the content has not changed since the last request.
These two functions are passed as arguments to the
django.views.decorators.http.conditionIn the decorator. This installation uses these two functions (if you can’t calculate it quickly and easily, you only need to provide one) to find out whether the protocol header in the HTTP request matches those resources. If they don’t match, a new copy of the resource is generated and your normal view is called.
conditionThe signature of the decorator is I:
The two functions that calculate the last modification time of Etag will be passed in the same order
requestObjects and the same parameters, just like the view functions they encapsulate.
last_modified_funcThe function should return a standard datetime value, which specifies the last time of resource modification, or the resource does not exist
None. Pass on to
etagThe decorator’s function should return a representation of the resourceEtagOr when the resource does not exist
It’s a good example of how to use this feature. Suppose you have these two models, which represent a simple blog system:
import datetime from django.db import models class Blog(models.Model): ... class Entry(models.Model): blog = models.ForeignKey(Blog) published = models.DateTimeField(default=datetime.datetime.now) ...
If the front page shows the last blog post and only changes it when you add a new post, you can calculate the last modification time very quickly. You need the end of every post on this blog
releaseDate. One way to achieve it is to:
def latest_entry(request, blog_id): return Entry.objects.filter(blog=blog_id).latest("published").published
Next, you can use this function to detect the unmodified page in advance for your front page view
from django.views.decorators.http import condition @condition(last_modified_func=latest_entry) def front_page(request, blog_id): ...
Shortcut to calculate only one value
A general principle is that if you provide a computational Etag_ And_ Finally, to modify the time function, you should do this: you don’t know which protocol header the HTTP client will send you, so you should be prepared to handle two situations. However, sometimes only one of the two is easy to calculate, and Django only provides you with a decorator to calculate Etag or last modified date.
conditionDecorator, passing in functions of the same type. Their signature is:
We can write an early example that just uses the function of the last modified date, using one of these decorators:
@last_modified(latest_entry) def front_page(request, blog_id): ...
def front_page(request, blog_id): ... front_page = last_modified(latest_entry)(front_page)
If you want to test two prerequisites, put
last_modifiedThe ornaments look nice chained together. However, this can lead to incorrect behavior:
# Bad code. Don't do this! @etag(etag_func) @last_modified(last_modified_func) def my_view(request): # ... # End of bad code.
The first decorator doesn’t know anything later and may send an “unmodified” response, even if the second decorator handles something else.
conditionThe decorator also uses two callback functions to figure out which is the right behavior.
Using decorators with other HTTP methods
conditionDecorators are not just for
HEADThe request is useful（
HEADRequest in this case and
GETSame). It can also be used for
DELETERequest for inspection. In these cases, it is not to return a “not modified (314)” response, but to tell the server that the resource they are trying to modify has been modified during this period.
For example, consider the following interactions between the client and the server:
The server replies with
Client sends http
/foo/To update resources. Also sent
If-Match: "abcd1234"Protocol header to specify the version to try to update.
The server checks to see if the resource has been modified
GETEtag is calculated in the same way as on (using the same function). If resourcesalreadyAfter modification, 412 status code will be returned, which means “precondition failed”.
After receiving the 412 response, the client sends the
/foo/To get a new version of the content before updating.
The important thing is that this example shows that Etag and last modification time values are calculated using the same function in all cases. Actually, youshouldUse the same function so that the same value is returned each time.
Use middleware to process on demand
You may notice that Django has passed
CommonMiddleware. provides simple and direct
GETOn demand. These middleware are easy to use and can be used in many situations. However, their functions have some limitations in advanced usage
They are used globally for all views in your project.
They don’t take the place of you generating the response itself, which can be costly.
They only apply to http
Here, you should choose the tool most suitable for your specific problem. If you have a way to quickly calculate Etag and modification time, and if some views need some time to generate content, you should consider using the method described in this document
conditionAdorner. If some of them are executed very fast, insisting on using middleware will also reduce the network traffic sent back to the client if the view is not modified.
This paper is based onCC BY-NC-SA 3.0Please keep the author’s signature and the source of the article.
Django document collaborative translation teamWe are short of staff. Interested friends can join us. It is totally public welfare. Communication group: 467338606.