1
0
mirror of https://github.com/django/django.git synced 2025-07-06 10:49:17 +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:
Malcolm Tredinnick 2007-11-03 02:16:27 +00:00
parent f189280eb3
commit 44df4e390f
13 changed files with 128 additions and 72 deletions

View File

@ -1,8 +1,8 @@
import time
from django.conf import settings
from django.utils.cache import patch_vary_headers
from email.Utils import formatdate
import datetime
import time
from django.utils.http import cookie_date
TEST_COOKIE_NAME = 'testcookie'
TEST_COOKIE_VALUE = 'worked'
@ -10,8 +10,9 @@ TEST_COOKIE_VALUE = 'worked'
class SessionMiddleware(object):
def process_request(self, request):
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
request.session = engine.SessionStore(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)
request.session = engine.SessionStore(session_key)
def process_response(self, request, response):
# If request.session was modified, or if response.session was set, save
@ -30,13 +31,8 @@ class SessionMiddleware(object):
expires = None
else:
max_age = settings.SESSION_COOKIE_AGE
rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
# 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")
expires_time = time.time() + settings.SESSION_COOKIE_AGE
expires = cookie_date(expires_time)
# Save the seesion data and refresh the client cookie.
request.session.save()
response.set_cookie(settings.SESSION_COOKIE_NAME,

View File

@ -9,14 +9,14 @@ been reviewed for security issues. Don't use it for production use.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from types import ListType, StringType
from email.Utils import formatdate
import mimetypes
import os
import re
import sys
import time
import urllib
from django.utils.http import http_date
__version__ = "0.1"
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
@ -376,7 +376,7 @@ class ServerHandler(object):
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
if 'Date' not in self.headers:
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:
self._write('Server: %s\r\n' % self.server_software)

View File

@ -1,4 +1,4 @@
from email.Utils import formatdate
from django.utils.http import http_date
class ConditionalGetMiddleware(object):
"""
@ -11,7 +11,7 @@ class ConditionalGetMiddleware(object):
Also sets the Date and Content-Length response-headers.
"""
def process_response(self, request, response):
response['Date'] = formatdate()[:26] + "GMT"
response['Date'] = http_date()
if not response.has_header('Content-Length'):
response['Content-Length'] = str(len(response.content))
@ -23,7 +23,6 @@ class ConditionalGetMiddleware(object):
response['Content-Length'] = '0'
if response.has_header('Last-Modified'):
last_mod = response['Last-Modified']
if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE', None)
if if_modified_since == response['Last-Modified']:
response.status_code = 304

View File

@ -6,7 +6,6 @@ and database field objects.
from django.utils.translation import ugettext
from django.utils.encoding import smart_unicode
from util import ValidationError
from forms import BaseForm, SortedDictFromList
from fields import Field, ChoiceField
@ -17,7 +16,8 @@ __all__ = (
'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``.
@ -27,15 +27,17 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
from django.db import models
opts = instance.__class__._meta
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
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
if fields and f.name not in fields:
continue
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():
opts = instance.__class__._meta
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:
f.save_form_data(instance, cleaned_data[f.name])
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()
save_m2m()
else:
# 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
return instance
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):
return save_instance(self, model(), fields, fail_message, commit)
return save
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):
return save_instance(self, instance, fields, fail_message, commit)
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.
@ -88,9 +91,11 @@ def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda
field_list.append((f.name, formfield))
base_fields = SortedDictFromList(field_list)
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.
@ -115,16 +120,22 @@ def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=l
field_list.append((f.name, formfield))
base_fields = SortedDictFromList(field_list)
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):
"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})
class QuerySetIterator(object):
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):
if self.empty_label is not None:
@ -136,11 +147,13 @@ class QuerySetIterator(object):
self.queryset._result_cache = None
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
# actually use any of ChoiceField's implementation.
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.empty_label = empty_label
self.cache_choices = cache_choices
@ -160,7 +173,8 @@ class ModelChoiceField(ChoiceField):
# *each* time _get_choices() is called (and, thus, each time
# self.choices is accessed) so that we can ensure the QuerySet has not
# 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):
# This method is copied from ChoiceField._set_choices(). It's necessary
@ -177,16 +191,20 @@ class ModelChoiceField(ChoiceField):
try:
value = self.queryset.model._default_manager.get(pk=value)
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
class ModelMultipleChoiceField(ModelChoiceField):
"A MultipleChoiceField whose choices are a model QuerySet."
"""A MultipleChoiceField whose choices are a model QuerySet."""
hidden_widget = MultipleHiddenInput
def __init__(self, queryset, cache_choices=False, required=True,
widget=SelectMultiple, label=None, initial=None, help_text=None):
super(ModelMultipleChoiceField, self).__init__(queryset, None, cache_choices,
required, widget, label, initial, help_text)
widget=SelectMultiple, label=None, initial=None,
help_text=None):
super(ModelMultipleChoiceField, self).__init__(queryset, None,
cache_choices, required, widget, label, initial, help_text)
def clean(self, value):
if self.required and not value:
@ -200,7 +218,9 @@ class ModelMultipleChoiceField(ModelChoiceField):
try:
obj = self.queryset.model._default_manager.get(pk=val)
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:
final_values.append(obj)
return final_values

View File

@ -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
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.
"""
import md5
import re
import time
from email.Utils import formatdate
from django.conf import settings
from django.core.cache import cache
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*')
@ -40,7 +41,7 @@ def patch_cache_control(response, **kwargs):
str() to it.
"""
def dictitem(s):
t = s.split('=',1)
t = s.split('=', 1)
if len(t) > 1:
return (t[0].lower(), t[1])
else:
@ -64,7 +65,7 @@ def patch_cache_control(response, **kwargs):
if 'max-age' in cc and 'max_age' in kwargs:
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 = ', '.join([dictvalue(el) for el in cc.items()])
response['Cache-Control'] = cc
@ -88,15 +89,14 @@ def patch_response_headers(response, cache_timeout=None):
if not response.has_header('ETag'):
response['ETag'] = md5.new(response.content).hexdigest()
if not response.has_header('Last-Modified'):
response['Last-Modified'] = formatdate()[:26] + "GMT"
response['Last-Modified'] = http_date()
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)
def add_never_cache_headers(response):
"""
Add headers to a response to indicate that
a page should never be cached.
Adds headers to a response to indicate that a page should never be cached.
"""
patch_response_headers(response, cache_timeout=-1)
@ -119,13 +119,14 @@ def patch_vary_headers(response, newheaders):
response['Vary'] = ', '.join(vary)
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()
for header in headerlist:
value = request.META.get(header, None)
if value is not None:
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):
"""
@ -139,7 +140,8 @@ def get_cache_key(request, key_prefix=None):
"""
if key_prefix is None:
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)
if headerlist is not None:
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
if cache_timeout is None:
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'):
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)
return _generate_cache_key(request, headerlist, key_prefix)
else:

View File

@ -1,4 +1,6 @@
import urllib
from email.Utils import formatdate
from django.utils.encoding import smart_str, force_unicode
from django.utils.functional import allow_lazy
@ -37,3 +39,29 @@ def urlencode(query, doseq=0):
for k, v in query],
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]

View File

@ -7,13 +7,14 @@ import mimetypes
import os
import posixpath
import re
import rfc822
import stat
import urllib
from email.Utils import parsedate_tz, mktime_tz
from django.template import loader
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified
from django.template import Template, Context, TemplateDoesNotExist
from django.utils.http import http_date
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]
contents = open(fullpath, 'rb').read()
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
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
@ -119,8 +120,7 @@ def was_modified_since(header=None, mtime=0, size=0):
raise ValueError
matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header,
re.IGNORECASE)
header_mtime = rfc822.mktime_tz(rfc822.parsedate_tz(
matches.group(1)))
header_mtime = mktime_tz(parsedate_tz(matches.group(1)))
header_len = matches.group(3)
if header_len and int(header_len) != size:
raise ValueError

View File

@ -291,13 +291,15 @@ minutes.
Template fragment caching
=========================
**New in development version**.
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 ``{%
load cache %}`` near the top of your template.
the ``cache`` template tag. To give your template access to this tag, put
``{% load cache %}`` near the top of your template.
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
seconds, and the name to give the cache fragment. For example::
amount of time. It takes at least two arguments: the cache timeout, in seconds,
and the name to give the cache fragment. For example::
{% load cache %}
{% cache 500 sidebar %}

View File

@ -275,7 +275,7 @@ The class has the following methods:
There are two ways to call ``attach()``:
* 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.
* Alternatively, you can pass ``attach()`` three arguments:

View File

@ -45,7 +45,7 @@ How to use ``FormPreview``
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
class SomeModelFormPreview(FormPreview):

View File

@ -150,7 +150,7 @@ mess things up. Use the ``PythonInterpreter`` directive to give different
<Location "/otherthing">
SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
PythonInterpreter mysite_other
PythonInterpreter othersite
</Location>
</VirtualHost>

View File

@ -721,7 +721,6 @@ This means, instead of instantiating a ``Client`` in each test::
...you can just refer to ``self.client``, like so::
from django.test import TestCase
from django.test.client import Client
class SimpleTest(TestCase):
def test_details(self):

View File

@ -27,6 +27,14 @@ u'Paris+%26+Orl%C3%A9ans'
>>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&")
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 ###########################################################
>>> from django.utils.encoding import iri_to_uri
>>> iri_to_uri(u'red%09ros\xe9#red')