mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Merged from trunk up to [6635].
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6638 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f189280eb3
commit
44df4e390f
@ -1,8 +1,8 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from email.Utils import formatdate
|
from django.utils.http import cookie_date
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
|
|
||||||
TEST_COOKIE_NAME = 'testcookie'
|
TEST_COOKIE_NAME = 'testcookie'
|
||||||
TEST_COOKIE_VALUE = 'worked'
|
TEST_COOKIE_VALUE = 'worked'
|
||||||
@ -10,8 +10,9 @@ TEST_COOKIE_VALUE = 'worked'
|
|||||||
class SessionMiddleware(object):
|
class SessionMiddleware(object):
|
||||||
|
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
|
||||||
request.session = engine.SessionStore(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
|
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
|
||||||
|
request.session = engine.SessionStore(session_key)
|
||||||
|
|
||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
# If request.session was modified, or if response.session was set, save
|
# If request.session was modified, or if response.session was set, save
|
||||||
@ -30,13 +31,8 @@ class SessionMiddleware(object):
|
|||||||
expires = None
|
expires = None
|
||||||
else:
|
else:
|
||||||
max_age = settings.SESSION_COOKIE_AGE
|
max_age = settings.SESSION_COOKIE_AGE
|
||||||
rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
|
expires_time = time.time() + settings.SESSION_COOKIE_AGE
|
||||||
|
expires = cookie_date(expires_time)
|
||||||
# Fixed length date must have '-' separation in the format
|
|
||||||
# DD-MMM-YYYY for compliance with Netscape cookie standard
|
|
||||||
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
|
|
||||||
datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
|
|
||||||
|
|
||||||
# Save the seesion data and refresh the client cookie.
|
# Save the seesion data and refresh the client cookie.
|
||||||
request.session.save()
|
request.session.save()
|
||||||
response.set_cookie(settings.SESSION_COOKIE_NAME,
|
response.set_cookie(settings.SESSION_COOKIE_NAME,
|
||||||
|
@ -9,14 +9,14 @@ been reviewed for security issues. Don't use it for production use.
|
|||||||
|
|
||||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||||
from types import ListType, StringType
|
from types import ListType, StringType
|
||||||
from email.Utils import formatdate
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
from django.utils.http import http_date
|
||||||
|
|
||||||
__version__ = "0.1"
|
__version__ = "0.1"
|
||||||
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
|
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ class ServerHandler(object):
|
|||||||
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
|
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
|
||||||
if 'Date' not in self.headers:
|
if 'Date' not in self.headers:
|
||||||
self._write(
|
self._write(
|
||||||
'Date: %s\r\n' % (formatdate()[:26] + "GMT")
|
'Date: %s\r\n' % http_date()
|
||||||
)
|
)
|
||||||
if self.server_software and 'Server' not in self.headers:
|
if self.server_software and 'Server' not in self.headers:
|
||||||
self._write('Server: %s\r\n' % self.server_software)
|
self._write('Server: %s\r\n' % self.server_software)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from email.Utils import formatdate
|
from django.utils.http import http_date
|
||||||
|
|
||||||
class ConditionalGetMiddleware(object):
|
class ConditionalGetMiddleware(object):
|
||||||
"""
|
"""
|
||||||
@ -11,7 +11,7 @@ class ConditionalGetMiddleware(object):
|
|||||||
Also sets the Date and Content-Length response-headers.
|
Also sets the Date and Content-Length response-headers.
|
||||||
"""
|
"""
|
||||||
def process_response(self, request, response):
|
def process_response(self, request, response):
|
||||||
response['Date'] = formatdate()[:26] + "GMT"
|
response['Date'] = http_date()
|
||||||
if not response.has_header('Content-Length'):
|
if not response.has_header('Content-Length'):
|
||||||
response['Content-Length'] = str(len(response.content))
|
response['Content-Length'] = str(len(response.content))
|
||||||
|
|
||||||
@ -23,7 +23,6 @@ class ConditionalGetMiddleware(object):
|
|||||||
response['Content-Length'] = '0'
|
response['Content-Length'] = '0'
|
||||||
|
|
||||||
if response.has_header('Last-Modified'):
|
if response.has_header('Last-Modified'):
|
||||||
last_mod = response['Last-Modified']
|
|
||||||
if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE', None)
|
if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE', None)
|
||||||
if if_modified_since == response['Last-Modified']:
|
if if_modified_since == response['Last-Modified']:
|
||||||
response.status_code = 304
|
response.status_code = 304
|
||||||
|
@ -6,7 +6,6 @@ and database field objects.
|
|||||||
from django.utils.translation import ugettext
|
from django.utils.translation import ugettext
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_unicode
|
||||||
|
|
||||||
|
|
||||||
from util import ValidationError
|
from util import ValidationError
|
||||||
from forms import BaseForm, SortedDictFromList
|
from forms import BaseForm, SortedDictFromList
|
||||||
from fields import Field, ChoiceField
|
from fields import Field, ChoiceField
|
||||||
@ -17,7 +16,8 @@ __all__ = (
|
|||||||
'ModelChoiceField', 'ModelMultipleChoiceField'
|
'ModelChoiceField', 'ModelMultipleChoiceField'
|
||||||
)
|
)
|
||||||
|
|
||||||
def save_instance(form, instance, fields=None, fail_message='saved', commit=True):
|
def save_instance(form, instance, fields=None, fail_message='saved',
|
||||||
|
commit=True):
|
||||||
"""
|
"""
|
||||||
Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
|
Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
|
||||||
|
|
||||||
@ -27,15 +27,17 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
opts = instance.__class__._meta
|
opts = instance.__class__._meta
|
||||||
if form.errors:
|
if form.errors:
|
||||||
raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message))
|
raise ValueError("The %s could not be %s because the data didn't"
|
||||||
|
" validate." % (opts.object_name, fail_message))
|
||||||
cleaned_data = form.cleaned_data
|
cleaned_data = form.cleaned_data
|
||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
if not f.editable or isinstance(f, models.AutoField) or not f.name in cleaned_data:
|
if not f.editable or isinstance(f, models.AutoField) \
|
||||||
|
or not f.name in cleaned_data:
|
||||||
continue
|
continue
|
||||||
if fields and f.name not in fields:
|
if fields and f.name not in fields:
|
||||||
continue
|
continue
|
||||||
f.save_form_data(instance, cleaned_data[f.name])
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
# Wrap up the saving of m2m data as a function
|
# Wrap up the saving of m2m data as a function.
|
||||||
def save_m2m():
|
def save_m2m():
|
||||||
opts = instance.__class__._meta
|
opts = instance.__class__._meta
|
||||||
cleaned_data = form.cleaned_data
|
cleaned_data = form.cleaned_data
|
||||||
@ -45,28 +47,29 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
|
|||||||
if f.name in cleaned_data:
|
if f.name in cleaned_data:
|
||||||
f.save_form_data(instance, cleaned_data[f.name])
|
f.save_form_data(instance, cleaned_data[f.name])
|
||||||
if commit:
|
if commit:
|
||||||
# If we are committing, save the instance and the m2m data immediately
|
# If we are committing, save the instance and the m2m data immediately.
|
||||||
instance.save()
|
instance.save()
|
||||||
save_m2m()
|
save_m2m()
|
||||||
else:
|
else:
|
||||||
# We're not committing. Add a method to the form to allow deferred
|
# We're not committing. Add a method to the form to allow deferred
|
||||||
# saving of m2m data
|
# saving of m2m data.
|
||||||
form.save_m2m = save_m2m
|
form.save_m2m = save_m2m
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def make_model_save(model, fields, fail_message):
|
def make_model_save(model, fields, fail_message):
|
||||||
"Returns the save() method for a Form."
|
"""Returns the save() method for a Form."""
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
return save_instance(self, model(), fields, fail_message, commit)
|
return save_instance(self, model(), fields, fail_message, commit)
|
||||||
return save
|
return save
|
||||||
|
|
||||||
def make_instance_save(instance, fields, fail_message):
|
def make_instance_save(instance, fields, fail_message):
|
||||||
"Returns the save() method for a Form."
|
"""Returns the save() method for a Form."""
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
return save_instance(self, instance, fields, fail_message, commit)
|
return save_instance(self, instance, fields, fail_message, commit)
|
||||||
return save
|
return save
|
||||||
|
|
||||||
def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda f: f.formfield()):
|
def form_for_model(model, form=BaseForm, fields=None,
|
||||||
|
formfield_callback=lambda f: f.formfield()):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for the given Django model class.
|
Returns a Form class for the given Django model class.
|
||||||
|
|
||||||
@ -88,9 +91,11 @@ def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda
|
|||||||
field_list.append((f.name, formfield))
|
field_list.append((f.name, formfield))
|
||||||
base_fields = SortedDictFromList(field_list)
|
base_fields = SortedDictFromList(field_list)
|
||||||
return type(opts.object_name + 'Form', (form,),
|
return type(opts.object_name + 'Form', (form,),
|
||||||
{'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')})
|
{'base_fields': base_fields, '_model': model,
|
||||||
|
'save': make_model_save(model, fields, 'created')})
|
||||||
|
|
||||||
def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
|
def form_for_instance(instance, form=BaseForm, fields=None,
|
||||||
|
formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for the given Django model instance.
|
Returns a Form class for the given Django model instance.
|
||||||
|
|
||||||
@ -115,16 +120,22 @@ def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=l
|
|||||||
field_list.append((f.name, formfield))
|
field_list.append((f.name, formfield))
|
||||||
base_fields = SortedDictFromList(field_list)
|
base_fields = SortedDictFromList(field_list)
|
||||||
return type(opts.object_name + 'InstanceForm', (form,),
|
return type(opts.object_name + 'InstanceForm', (form,),
|
||||||
{'base_fields': base_fields, '_model': model, 'save': make_instance_save(instance, fields, 'changed')})
|
{'base_fields': base_fields, '_model': model,
|
||||||
|
'save': make_instance_save(instance, fields, 'changed')})
|
||||||
|
|
||||||
def form_for_fields(field_list):
|
def form_for_fields(field_list):
|
||||||
"Returns a Form class for the given list of Django database field instances."
|
"""
|
||||||
fields = SortedDictFromList([(f.name, f.formfield()) for f in field_list if f.editable])
|
Returns a Form class for the given list of Django database field instances.
|
||||||
|
"""
|
||||||
|
fields = SortedDictFromList([(f.name, f.formfield())
|
||||||
|
for f in field_list if f.editable])
|
||||||
return type('FormForFields', (BaseForm,), {'base_fields': fields})
|
return type('FormForFields', (BaseForm,), {'base_fields': fields})
|
||||||
|
|
||||||
class QuerySetIterator(object):
|
class QuerySetIterator(object):
|
||||||
def __init__(self, queryset, empty_label, cache_choices):
|
def __init__(self, queryset, empty_label, cache_choices):
|
||||||
self.queryset, self.empty_label, self.cache_choices = queryset, empty_label, cache_choices
|
self.queryset = queryset
|
||||||
|
self.empty_label = empty_label
|
||||||
|
self.cache_choices = cache_choices
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
if self.empty_label is not None:
|
if self.empty_label is not None:
|
||||||
@ -136,11 +147,13 @@ class QuerySetIterator(object):
|
|||||||
self.queryset._result_cache = None
|
self.queryset._result_cache = None
|
||||||
|
|
||||||
class ModelChoiceField(ChoiceField):
|
class ModelChoiceField(ChoiceField):
|
||||||
"A ChoiceField whose choices are a model QuerySet."
|
"""A ChoiceField whose choices are a model QuerySet."""
|
||||||
# This class is a subclass of ChoiceField for purity, but it doesn't
|
# This class is a subclass of ChoiceField for purity, but it doesn't
|
||||||
# actually use any of ChoiceField's implementation.
|
# actually use any of ChoiceField's implementation.
|
||||||
|
|
||||||
def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
|
def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
|
||||||
required=True, widget=Select, label=None, initial=None, help_text=None):
|
required=True, widget=Select, label=None, initial=None,
|
||||||
|
help_text=None):
|
||||||
self.queryset = queryset
|
self.queryset = queryset
|
||||||
self.empty_label = empty_label
|
self.empty_label = empty_label
|
||||||
self.cache_choices = cache_choices
|
self.cache_choices = cache_choices
|
||||||
@ -160,7 +173,8 @@ class ModelChoiceField(ChoiceField):
|
|||||||
# *each* time _get_choices() is called (and, thus, each time
|
# *each* time _get_choices() is called (and, thus, each time
|
||||||
# self.choices is accessed) so that we can ensure the QuerySet has not
|
# self.choices is accessed) so that we can ensure the QuerySet has not
|
||||||
# been consumed.
|
# been consumed.
|
||||||
return QuerySetIterator(self.queryset, self.empty_label, self.cache_choices)
|
return QuerySetIterator(self.queryset, self.empty_label,
|
||||||
|
self.cache_choices)
|
||||||
|
|
||||||
def _set_choices(self, value):
|
def _set_choices(self, value):
|
||||||
# This method is copied from ChoiceField._set_choices(). It's necessary
|
# This method is copied from ChoiceField._set_choices(). It's necessary
|
||||||
@ -177,16 +191,20 @@ class ModelChoiceField(ChoiceField):
|
|||||||
try:
|
try:
|
||||||
value = self.queryset.model._default_manager.get(pk=value)
|
value = self.queryset.model._default_manager.get(pk=value)
|
||||||
except self.queryset.model.DoesNotExist:
|
except self.queryset.model.DoesNotExist:
|
||||||
raise ValidationError(ugettext(u'Select a valid choice. That choice is not one of the available choices.'))
|
raise ValidationError(ugettext(u'Select a valid choice. That'
|
||||||
|
u' choice is not one of the'
|
||||||
|
u' available choices.'))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
class ModelMultipleChoiceField(ModelChoiceField):
|
class ModelMultipleChoiceField(ModelChoiceField):
|
||||||
"A MultipleChoiceField whose choices are a model QuerySet."
|
"""A MultipleChoiceField whose choices are a model QuerySet."""
|
||||||
hidden_widget = MultipleHiddenInput
|
hidden_widget = MultipleHiddenInput
|
||||||
|
|
||||||
def __init__(self, queryset, cache_choices=False, required=True,
|
def __init__(self, queryset, cache_choices=False, required=True,
|
||||||
widget=SelectMultiple, label=None, initial=None, help_text=None):
|
widget=SelectMultiple, label=None, initial=None,
|
||||||
super(ModelMultipleChoiceField, self).__init__(queryset, None, cache_choices,
|
help_text=None):
|
||||||
required, widget, label, initial, help_text)
|
super(ModelMultipleChoiceField, self).__init__(queryset, None,
|
||||||
|
cache_choices, required, widget, label, initial, help_text)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
if self.required and not value:
|
if self.required and not value:
|
||||||
@ -200,7 +218,9 @@ class ModelMultipleChoiceField(ModelChoiceField):
|
|||||||
try:
|
try:
|
||||||
obj = self.queryset.model._default_manager.get(pk=val)
|
obj = self.queryset.model._default_manager.get(pk=val)
|
||||||
except self.queryset.model.DoesNotExist:
|
except self.queryset.model.DoesNotExist:
|
||||||
raise ValidationError(ugettext(u'Select a valid choice. %s is not one of the available choices.') % val)
|
raise ValidationError(ugettext(u'Select a valid choice. %s is'
|
||||||
|
u' not one of the available'
|
||||||
|
u' choices.') % val)
|
||||||
else:
|
else:
|
||||||
final_values.append(obj)
|
final_values.append(obj)
|
||||||
return final_values
|
return final_values
|
||||||
|
@ -13,17 +13,18 @@ into account when building its cache key. Requests with the same path but
|
|||||||
different header content for headers named in "Vary" need to get different
|
different header content for headers named in "Vary" need to get different
|
||||||
cache keys to prevent delivery of wrong content.
|
cache keys to prevent delivery of wrong content.
|
||||||
|
|
||||||
A example: i18n middleware would need to distinguish caches by the
|
An example: i18n middleware would need to distinguish caches by the
|
||||||
"Accept-language" header.
|
"Accept-language" header.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import md5
|
import md5
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from email.Utils import formatdate
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.encoding import smart_str, iri_to_uri
|
from django.utils.encoding import smart_str, iri_to_uri
|
||||||
|
from django.utils.http import http_date
|
||||||
|
|
||||||
cc_delim_re = re.compile(r'\s*,\s*')
|
cc_delim_re = re.compile(r'\s*,\s*')
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ def patch_cache_control(response, **kwargs):
|
|||||||
str() to it.
|
str() to it.
|
||||||
"""
|
"""
|
||||||
def dictitem(s):
|
def dictitem(s):
|
||||||
t = s.split('=',1)
|
t = s.split('=', 1)
|
||||||
if len(t) > 1:
|
if len(t) > 1:
|
||||||
return (t[0].lower(), t[1])
|
return (t[0].lower(), t[1])
|
||||||
else:
|
else:
|
||||||
@ -64,7 +65,7 @@ def patch_cache_control(response, **kwargs):
|
|||||||
if 'max-age' in cc and 'max_age' in kwargs:
|
if 'max-age' in cc and 'max_age' in kwargs:
|
||||||
kwargs['max_age'] = min(cc['max-age'], kwargs['max_age'])
|
kwargs['max_age'] = min(cc['max-age'], kwargs['max_age'])
|
||||||
|
|
||||||
for (k,v) in kwargs.items():
|
for (k, v) in kwargs.items():
|
||||||
cc[k.replace('_', '-')] = v
|
cc[k.replace('_', '-')] = v
|
||||||
cc = ', '.join([dictvalue(el) for el in cc.items()])
|
cc = ', '.join([dictvalue(el) for el in cc.items()])
|
||||||
response['Cache-Control'] = cc
|
response['Cache-Control'] = cc
|
||||||
@ -88,15 +89,14 @@ def patch_response_headers(response, cache_timeout=None):
|
|||||||
if not response.has_header('ETag'):
|
if not response.has_header('ETag'):
|
||||||
response['ETag'] = md5.new(response.content).hexdigest()
|
response['ETag'] = md5.new(response.content).hexdigest()
|
||||||
if not response.has_header('Last-Modified'):
|
if not response.has_header('Last-Modified'):
|
||||||
response['Last-Modified'] = formatdate()[:26] + "GMT"
|
response['Last-Modified'] = http_date()
|
||||||
if not response.has_header('Expires'):
|
if not response.has_header('Expires'):
|
||||||
response['Expires'] = formatdate(time.time() + cache_timeout)[:26] + "GMT"
|
response['Expires'] = http_date(time.time() + cache_timeout)
|
||||||
patch_cache_control(response, max_age=cache_timeout)
|
patch_cache_control(response, max_age=cache_timeout)
|
||||||
|
|
||||||
def add_never_cache_headers(response):
|
def add_never_cache_headers(response):
|
||||||
"""
|
"""
|
||||||
Add headers to a response to indicate that
|
Adds headers to a response to indicate that a page should never be cached.
|
||||||
a page should never be cached.
|
|
||||||
"""
|
"""
|
||||||
patch_response_headers(response, cache_timeout=-1)
|
patch_response_headers(response, cache_timeout=-1)
|
||||||
|
|
||||||
@ -119,13 +119,14 @@ def patch_vary_headers(response, newheaders):
|
|||||||
response['Vary'] = ', '.join(vary)
|
response['Vary'] = ', '.join(vary)
|
||||||
|
|
||||||
def _generate_cache_key(request, headerlist, key_prefix):
|
def _generate_cache_key(request, headerlist, key_prefix):
|
||||||
"Returns a cache key from the headers given in the header list."
|
"""Returns a cache key from the headers given in the header list."""
|
||||||
ctx = md5.new()
|
ctx = md5.new()
|
||||||
for header in headerlist:
|
for header in headerlist:
|
||||||
value = request.META.get(header, None)
|
value = request.META.get(header, None)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
ctx.update(value)
|
ctx.update(value)
|
||||||
return 'views.decorators.cache.cache_page.%s.%s.%s' % (key_prefix, iri_to_uri(request.path), ctx.hexdigest())
|
return 'views.decorators.cache.cache_page.%s.%s.%s' % (
|
||||||
|
key_prefix, iri_to_uri(request.path), ctx.hexdigest())
|
||||||
|
|
||||||
def get_cache_key(request, key_prefix=None):
|
def get_cache_key(request, key_prefix=None):
|
||||||
"""
|
"""
|
||||||
@ -139,7 +140,8 @@ def get_cache_key(request, key_prefix=None):
|
|||||||
"""
|
"""
|
||||||
if key_prefix is None:
|
if key_prefix is None:
|
||||||
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, iri_to_uri(request.path))
|
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
||||||
|
key_prefix, iri_to_uri(request.path))
|
||||||
headerlist = cache.get(cache_key, None)
|
headerlist = cache.get(cache_key, None)
|
||||||
if headerlist is not None:
|
if headerlist is not None:
|
||||||
return _generate_cache_key(request, headerlist, key_prefix)
|
return _generate_cache_key(request, headerlist, key_prefix)
|
||||||
@ -163,9 +165,11 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
|
|||||||
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
||||||
if cache_timeout is None:
|
if cache_timeout is None:
|
||||||
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
||||||
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (key_prefix, iri_to_uri(request.path))
|
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
||||||
|
key_prefix, iri_to_uri(request.path))
|
||||||
if response.has_header('Vary'):
|
if response.has_header('Vary'):
|
||||||
headerlist = ['HTTP_'+header.upper().replace('-', '_') for header in vary_delim_re.split(response['Vary'])]
|
headerlist = ['HTTP_'+header.upper().replace('-', '_')
|
||||||
|
for header in vary_delim_re.split(response['Vary'])]
|
||||||
cache.set(cache_key, headerlist, cache_timeout)
|
cache.set(cache_key, headerlist, cache_timeout)
|
||||||
return _generate_cache_key(request, headerlist, key_prefix)
|
return _generate_cache_key(request, headerlist, key_prefix)
|
||||||
else:
|
else:
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import urllib
|
import urllib
|
||||||
|
from email.Utils import formatdate
|
||||||
|
|
||||||
from django.utils.encoding import smart_str, force_unicode
|
from django.utils.encoding import smart_str, force_unicode
|
||||||
from django.utils.functional import allow_lazy
|
from django.utils.functional import allow_lazy
|
||||||
|
|
||||||
@ -37,3 +39,29 @@ def urlencode(query, doseq=0):
|
|||||||
for k, v in query],
|
for k, v in query],
|
||||||
doseq)
|
doseq)
|
||||||
|
|
||||||
|
def cookie_date(epoch_seconds=None):
|
||||||
|
"""
|
||||||
|
Formats the time to ensure compatibility with Netscape's cookie standard.
|
||||||
|
|
||||||
|
Accepts a floating point number expressed in seconds since the epoch, in
|
||||||
|
UTC - such as that outputted by time.time(). If set to None, defaults to
|
||||||
|
the current time.
|
||||||
|
|
||||||
|
Outputs a string in the format 'Wdy, DD-Mon-YYYY HH:MM:SS GMT'.
|
||||||
|
"""
|
||||||
|
rfcdate = formatdate(epoch_seconds)
|
||||||
|
return '%s-%s-%s GMT' % (rfcdate[:7], rfcdate[8:11], rfcdate[12:25])
|
||||||
|
|
||||||
|
def http_date(epoch_seconds=None):
|
||||||
|
"""
|
||||||
|
Formats the time to match the RFC1123 date format as specified by HTTP
|
||||||
|
RFC2616 section 3.3.1.
|
||||||
|
|
||||||
|
Accepts a floating point number expressed in seconds since the epoch, in
|
||||||
|
UTC - such as that outputted by time.time(). If set to None, defaults to
|
||||||
|
the current time.
|
||||||
|
|
||||||
|
Outputs a string in the format 'Wdy, DD Mon YYYY HH:MM:SS GMT'.
|
||||||
|
"""
|
||||||
|
rfcdate = formatdate(epoch_seconds)
|
||||||
|
return '%s GMT' % rfcdate[:25]
|
||||||
|
@ -7,13 +7,14 @@ import mimetypes
|
|||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
import re
|
import re
|
||||||
import rfc822
|
|
||||||
import stat
|
import stat
|
||||||
import urllib
|
import urllib
|
||||||
|
from email.Utils import parsedate_tz, mktime_tz
|
||||||
|
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified
|
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified
|
||||||
from django.template import Template, Context, TemplateDoesNotExist
|
from django.template import Template, Context, TemplateDoesNotExist
|
||||||
|
from django.utils.http import http_date
|
||||||
|
|
||||||
def serve(request, path, document_root=None, show_indexes=False):
|
def serve(request, path, document_root=None, show_indexes=False):
|
||||||
"""
|
"""
|
||||||
@ -60,7 +61,7 @@ def serve(request, path, document_root=None, show_indexes=False):
|
|||||||
mimetype = mimetypes.guess_type(fullpath)[0]
|
mimetype = mimetypes.guess_type(fullpath)[0]
|
||||||
contents = open(fullpath, 'rb').read()
|
contents = open(fullpath, 'rb').read()
|
||||||
response = HttpResponse(contents, mimetype=mimetype)
|
response = HttpResponse(contents, mimetype=mimetype)
|
||||||
response["Last-Modified"] = rfc822.formatdate(statobj[stat.ST_MTIME])
|
response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
|
||||||
return response
|
return response
|
||||||
|
|
||||||
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
|
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
|
||||||
@ -119,8 +120,7 @@ def was_modified_since(header=None, mtime=0, size=0):
|
|||||||
raise ValueError
|
raise ValueError
|
||||||
matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header,
|
matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header,
|
||||||
re.IGNORECASE)
|
re.IGNORECASE)
|
||||||
header_mtime = rfc822.mktime_tz(rfc822.parsedate_tz(
|
header_mtime = mktime_tz(parsedate_tz(matches.group(1)))
|
||||||
matches.group(1)))
|
|
||||||
header_len = matches.group(3)
|
header_len = matches.group(3)
|
||||||
if header_len and int(header_len) != size:
|
if header_len and int(header_len) != size:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
@ -291,13 +291,15 @@ minutes.
|
|||||||
Template fragment caching
|
Template fragment caching
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
**New in development version**.
|
||||||
|
|
||||||
If you're after even more control, you can also cache template fragments using
|
If you're after even more control, you can also cache template fragments using
|
||||||
the ``cache`` template tag. To give your template access to this tag, put ``{%
|
the ``cache`` template tag. To give your template access to this tag, put
|
||||||
load cache %}`` near the top of your template.
|
``{% load cache %}`` near the top of your template.
|
||||||
|
|
||||||
The ``{% cache %}`` template tag caches the contents of the block for a given
|
The ``{% cache %}`` template tag caches the contents of the block for a given
|
||||||
amount of time. It takes at least two arguments: the cache timeout, in
|
amount of time. It takes at least two arguments: the cache timeout, in seconds,
|
||||||
seconds, and the name to give the cache fragment. For example::
|
and the name to give the cache fragment. For example::
|
||||||
|
|
||||||
{% load cache %}
|
{% load cache %}
|
||||||
{% cache 500 sidebar %}
|
{% cache 500 sidebar %}
|
||||||
|
@ -275,7 +275,7 @@ The class has the following methods:
|
|||||||
There are two ways to call ``attach()``:
|
There are two ways to call ``attach()``:
|
||||||
|
|
||||||
* You can pass it a single argument that is an
|
* You can pass it a single argument that is an
|
||||||
``email.MIMBase.MIMEBase`` instance. This will be inserted directly
|
``email.MIMEBase.MIMEBase`` instance. This will be inserted directly
|
||||||
into the resulting message.
|
into the resulting message.
|
||||||
|
|
||||||
* Alternatively, you can pass ``attach()`` three arguments:
|
* Alternatively, you can pass ``attach()`` three arguments:
|
||||||
|
@ -45,7 +45,7 @@ How to use ``FormPreview``
|
|||||||
|
|
||||||
2. Create a ``FormPreview`` subclass that overrides the ``done()`` method::
|
2. Create a ``FormPreview`` subclass that overrides the ``done()`` method::
|
||||||
|
|
||||||
from django.contrib.formtools import FormPreview
|
from django.contrib.formtools.preview import FormPreview
|
||||||
from myapp.models import SomeModel
|
from myapp.models import SomeModel
|
||||||
|
|
||||||
class SomeModelFormPreview(FormPreview):
|
class SomeModelFormPreview(FormPreview):
|
||||||
|
@ -150,7 +150,7 @@ mess things up. Use the ``PythonInterpreter`` directive to give different
|
|||||||
|
|
||||||
<Location "/otherthing">
|
<Location "/otherthing">
|
||||||
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
|
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
|
||||||
PythonInterpreter mysite_other
|
PythonInterpreter othersite
|
||||||
</Location>
|
</Location>
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
|
||||||
|
@ -721,7 +721,6 @@ This means, instead of instantiating a ``Client`` in each test::
|
|||||||
...you can just refer to ``self.client``, like so::
|
...you can just refer to ``self.client``, like so::
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
class SimpleTest(TestCase):
|
||||||
def test_details(self):
|
def test_details(self):
|
||||||
|
@ -27,6 +27,14 @@ u'Paris+%26+Orl%C3%A9ans'
|
|||||||
>>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&")
|
>>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&")
|
||||||
u'Paris+&+Orl%C3%A9ans'
|
u'Paris+&+Orl%C3%A9ans'
|
||||||
|
|
||||||
|
### cookie_date, http_date ###############################################
|
||||||
|
>>> from django.utils.http import cookie_date, http_date
|
||||||
|
>>> t = 1167616461.0
|
||||||
|
>>> cookie_date(t)
|
||||||
|
'Mon, 01-Jan-2007 01:54:21 GMT'
|
||||||
|
>>> http_date(t)
|
||||||
|
'Mon, 01 Jan 2007 01:54:21 GMT'
|
||||||
|
|
||||||
### iri_to_uri ###########################################################
|
### iri_to_uri ###########################################################
|
||||||
>>> from django.utils.encoding import iri_to_uri
|
>>> from django.utils.encoding import iri_to_uri
|
||||||
>>> iri_to_uri(u'red%09ros\xe9#red')
|
>>> iri_to_uri(u'red%09ros\xe9#red')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user