Changeset 815
- Timestamp:
- 10/09/05 05:47:06 (3 years ago)
- Files:
-
- django/branches/i18n/django/bin/django-admin.py (modified) (2 diffs)
- django/branches/i18n/django/conf/global_settings.py (modified) (2 diffs)
- django/branches/i18n/django/core/db/backends/mysql.py (modified) (2 diffs)
- django/branches/i18n/django/core/management.py (modified) (5 diffs)
- django/branches/i18n/django/core/meta/fields.py (modified) (1 diff)
- django/branches/i18n/django/core/meta/__init__.py (modified) (1 diff)
- django/branches/i18n/django/middleware/cache.py (modified) (1 diff)
- django/branches/i18n/django/middleware/gzip.py (copied) (copied from django/trunk/django/middleware/gzip.py)
- django/branches/i18n/django/middleware/http.py (copied) (copied from django/trunk/django/middleware/http.py)
- django/branches/i18n/django/middleware/sessions.py (modified) (2 diffs)
- django/branches/i18n/django/utils/cache.py (copied) (copied from django/trunk/django/utils/cache.py)
- django/branches/i18n/django/utils/decorators.py (copied) (copied from django/trunk/django/utils/decorators.py)
- django/branches/i18n/django/views/admin/main.py (modified) (1 diff)
- django/branches/i18n/django/views/decorators/cache.py (modified) (1 diff)
- django/branches/i18n/django/views/decorators/gzip.py (copied) (copied from django/trunk/django/views/decorators/gzip.py)
- django/branches/i18n/django/views/decorators/http.py (copied) (copied from django/trunk/django/views/decorators/http.py)
- django/branches/i18n/django/views/decorators/vary.py (copied) (copied from django/trunk/django/views/decorators/vary.py)
- django/branches/i18n/docs/cache.txt (modified) (9 diffs)
- django/branches/i18n/docs/django-admin.txt (modified) (2 diffs)
- django/branches/i18n/docs/middleware.txt (modified) (1 diff)
- django/branches/i18n/tests/runtests.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/i18n/django/bin/django-admin.py
r692 r815 54 54 parser.add_option('--settings', 55 55 help='Python path to settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.') 56 parser.add_option('--pythonpath', 57 help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".') 56 58 options, args = parser.parse_args() 57 59 … … 59 61 if options.settings: 60 62 os.environ['DJANGO_SETTINGS_MODULE'] = options.settings 63 if options.pythonpath: 64 sys.path.insert(0, options.pythonpath) 61 65 62 66 # Run the appropriate action. Unfortunately, optparse can't handle django/branches/i18n/django/conf/global_settings.py
r787 r815 137 137 MIDDLEWARE_CLASSES = ( 138 138 "django.middleware.sessions.SessionMiddleware", 139 # "django.middleware.http.ConditionalGetMiddleware", 140 # "django.middleware.gzip.GZipMiddleware", 139 141 "django.middleware.common.CommonMiddleware", 140 142 "django.middleware.doc.XViewMiddleware", … … 156 158 # possible values. 157 159 CACHE_BACKEND = 'simple://' 160 CACHE_MIDDLEWARE_KEY_PREFIX = '' 158 161 159 162 #################### django/branches/i18n/django/core/db/backends/mysql.py
r713 r815 22 22 }) 23 23 24 # This is an extra debug layer over MySQL queries, to display warnings. 25 # It's only used when DEBUG=True. 26 class MysqlDebugWrapper: 27 def __init__(self, cursor): 28 self.cursor = cursor 29 30 def execute(self, sql, params=()): 31 try: 32 return self.cursor.execute(sql, params) 33 except Database.Warning, w: 34 self.cursor.execute("SHOW WARNINGS") 35 raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall()) 36 37 def executemany(self, sql, param_list): 38 try: 39 return self.cursor.executemany(sql, param_list) 40 except Database.Warning: 41 self.cursor.execute("SHOW WARNINGS") 42 raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall()) 43 44 def __getattr__(self, attr): 45 if self.__dict__.has_key(attr): 46 return self.__dict__[attr] 47 else: 48 return getattr(self.cursor, attr) 49 24 50 class DatabaseWrapper: 25 51 def __init__(self): … … 33 59 passwd=DATABASE_PASSWORD, host=DATABASE_HOST, conv=django_conversions) 34 60 if DEBUG: 35 return base.CursorDebugWrapper( self.connection.cursor(), self)61 return base.CursorDebugWrapper(MysqlDebugWrapper(self.connection.cursor()), self) 36 62 return self.connection.cursor() 37 63 django/branches/i18n/django/core/management.py
r787 r815 17 17 # Use django.__path__[0] because we don't know which directory django into 18 18 # which has been installed. 19 PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf /%s_template')20 ADMIN_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf /admin_templates')19 PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template') 20 ADMIN_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', 'admin_templates') 21 21 22 22 def _get_packages_insert(app_label): … … 161 161 app_label = mod._MODELS[0]._meta.app_label 162 162 output.append(_get_packages_insert(app_label)) 163 app_dir = os.path.normpath(os.path.join(os.path.dirname(mod.__file__), '.. /sql'))163 app_dir = os.path.normpath(os.path.join(os.path.dirname(mod.__file__), '..', 'sql')) 164 164 for klass in mod._MODELS: 165 165 opts = klass._meta … … 377 377 # Populate TEMPLATE_DIRS for the admin templates, based on where Django is 378 378 # installed. 379 admin_settings_file = os.path.join(directory, project_name, 'settings /admin.py')379 admin_settings_file = os.path.join(directory, project_name, 'settings', 'admin.py') 380 380 settings_contents = open(admin_settings_file, 'r').read() 381 381 fp = open(admin_settings_file, 'w') … … 384 384 fp.close() 385 385 # Create a random SECRET_KEY hash, and put it in the main settings. 386 main_settings_file = os.path.join(directory, project_name, 'settings /main.py')386 main_settings_file = os.path.join(directory, project_name, 'settings', 'main.py') 387 387 settings_contents = open(main_settings_file, 'r').read() 388 388 fp = open(main_settings_file, 'w') … … 398 398 # Determine the project_name a bit naively -- by looking at the name of 399 399 # the parent directory. 400 project_dir = os.path.normpath(os.path.join(directory, '.. /'))400 project_dir = os.path.normpath(os.path.join(directory, '..')) 401 401 project_name = os.path.basename(project_dir) 402 402 _start_helper('app', app_name, directory, project_name) django/branches/i18n/django/core/meta/fields.py
r713 r815 597 597 598 598 def get_manipulator_field_objs(self): 599 return [formfields.IntegerField] 599 rel_field = self.rel.get_related_field() 600 if self.rel.raw_id_admin and not isinstance(rel_field, AutoField): 601 return rel_field.get_manipulator_field_objs() 602 else: 603 return [formfields.IntegerField] 600 604 601 605 class ManyToManyField(Field): django/branches/i18n/django/core/meta/__init__.py
r698 r815 1333 1333 order_by.append(db.get_random_function_sql()) 1334 1334 else: 1335 if f.startswith('-'): 1336 col_name = f[1:] 1337 order = "DESC" 1338 else: 1339 col_name = f 1340 order = "ASC" 1335 1341 # Use the database table as a column prefix if it wasn't given, 1336 1342 # and if the requested column isn't a custom SELECT. 1337 if "." not in f and fnot in [k[0] for k in kwargs.get('select', [])]:1343 if "." not in col_name and col_name not in [k[0] for k in kwargs.get('select', [])]: 1338 1344 table_prefix = opts.db_table + '.' 1339 1345 else: 1340 1346 table_prefix = '' 1341 if f.startswith('-'): 1342 order_by.append('%s%s DESC' % (table_prefix, orderfield2column(f[1:], opts))) 1343 else: 1344 order_by.append('%s%s ASC' % (table_prefix, orderfield2column(f, opts))) 1347 order_by.append('%s%s %s' % (table_prefix, orderfield2column(col_name, opts), order)) 1345 1348 order_by = ", ".join(order_by) 1346 1349 django/branches/i18n/django/middleware/cache.py
r787 r815 1 import copy 1 2 from django.conf import settings 2 3 from django.core.cache import cache 4 from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers 3 5 from django.utils.httpwrappers import HttpResponseNotModified 4 from django.utils.text import compress_string5 import datetime, md56 6 7 7 class CacheMiddleware: 8 8 """ 9 9 Cache middleware. If this is enabled, each Django-powered page will be 10 cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs. Pages 11 with GET or POST parameters are not cached. 10 cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs. 12 11 13 If the cache is shared across multiple sites using the same Django 14 installation, set the CACHE_MIDDLEWARE_KEY_PREFIX to the name of the site, 15 or some other string that is unique to this Django instance, to prevent key 16 collisions. 12 Only parameter-less GET or HEAD-requests with status code 200 are cached. 17 13 18 This middleware will also make the following optimizations: 14 This middleware expects that a HEAD request is answered with a response 15 exactly like the corresponding GET request. 19 16 20 * If the CACHE_MIDDLEWARE_GZIP setting is True, the content will be21 gzipped.17 When a hit occurs, a shallow copy of the original response object is 18 returned from process_request. 22 19 23 * ETags will be added, using a simple MD5 hash of the page's content. 20 Pages will be cached based on the contents of the request headers 21 listed in the response's "Vary" header. This means that pages shouldn't 22 change their "Vary" header. 23 24 This middleware also sets ETag, Last-Modified, Expires and Cache-Control 25 headers on the response object. 24 26 """ 27 def __init__(self, cache_timeout=None, key_prefix=None): 28 self.cache_timeout = cache_timeout 29 if cache_timeout is None: 30 self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS 31 self.key_prefix = key_prefix 32 if key_prefix is None: 33 self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX 34 25 35 def process_request(self, request): 26 """ 27 Checks whether the page is already cached. If it is, returns the cached 28 version. Also handles ETag stuff. 29 """ 30 if request.GET or request.POST: 31 request._cache_middleware_set_cache = False 36 "Checks whether the page is already cached and returns the cached version if available." 37 if not request.META['REQUEST_METHOD'] in ('GET', 'HEAD') or request.GET: 38 request._cache_update_cache = False 32 39 return None # Don't bother checking the cache. 33 40 34 accept_encoding = '' 35 if settings.CACHE_MIDDLEWARE_GZIP: 36 try: 37 accept_encoding = request.META['HTTP_ACCEPT_ENCODING'] 38 except KeyError: 39 pass 40 accepts_gzip = 'gzip' in accept_encoding 41 request._cache_middleware_accepts_gzip = accepts_gzip 42 43 # This uses the same cache_key as views.decorators.cache.cache_page, 44 # so the cache can be shared. 45 cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % \ 46 (settings.CACHE_MIDDLEWARE_KEY_PREFIX, request.path, accepts_gzip) 47 request._cache_middleware_key = cache_key 41 cache_key = get_cache_key(request, self.key_prefix) 42 if cache_key is None: 43 request._cache_update_cache = True 44 return None # No cache information available, need to rebuild. 48 45 49 46 response = cache.get(cache_key, None) 50 47 if response is None: 51 request._cache_middleware_set_cache = True 52 return None 53 else: 54 request._cache_middleware_set_cache = False 55 # Logic is from http://simon.incutio.com/archive/2003/04/23/conditionalGet 56 try: 57 if_none_match = request.META['HTTP_IF_NONE_MATCH'] 58 except KeyError: 59 if_none_match = None 60 try: 61 if_modified_since = request.META['HTTP_IF_MODIFIED_SINCE'] 62 except KeyError: 63 if_modified_since = None 64 if if_none_match is None and if_modified_since is None: 65 pass 66 elif if_none_match is not None and response['ETag'] != if_none_match: 67 pass 68 elif if_modified_since is not None and response['Last-Modified'] != if_modified_since: 69 pass 70 else: 71 return HttpResponseNotModified() 72 return response 48 request._cache_update_cache = True 49 return None # No cache information available, need to rebuild. 50 51 request._cache_update_cache = False 52 return copy.copy(response) 73 53 74 54 def process_response(self, request, response): 75 """ 76 Sets the cache, if needed. 77 """ 78 if request._cache_middleware_set_cache: 79 content = response.get_content_as_string(settings.DEFAULT_CHARSET) 80 if request._cache_middleware_accepts_gzip: 81 content = compress_string(content) 82 response.content = content 83 response['Content-Encoding'] = 'gzip' 84 response['ETag'] = md5.new(content).hexdigest() 85 response['Content-Length'] = '%d' % len(content) 86 response['Last-Modified'] = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') 87 cache.set(request._cache_middleware_key, response, settings.CACHE_MIDDLEWARE_SECONDS) 55 "Sets the cache, if needed." 56 if not request._cache_update_cache: 57 # We don't need to update the cache, just return. 58 return response 59 if not request.META['REQUEST_METHOD'] == 'GET': 60 # This is a stronger requirement than above. It is needed 61 # because of interactions between this middleware and the 62 # HTTPMiddleware, which throws the body of a HEAD-request 63 # away before this middleware gets a chance to cache it. 64 return response 65 if not response.status_code == 200: 66 return response 67 patch_response_headers(response, self.cache_timeout) 68 cache_key = learn_cache_key(request, response, self.cache_timeout, self.key_prefix) 69 cache.set(cache_key, response, self.cache_timeout) 88 70 return response django/branches/i18n/django/middleware/sessions.py
r669 r815 1 1 from django.conf.settings import SESSION_COOKIE_NAME, SESSION_COOKIE_AGE, SESSION_COOKIE_DOMAIN 2 2 from django.models.core import sessions 3 from django.utils.cache import patch_vary_headers 3 4 import datetime 4 5 … … 62 63 # If request.session was modified, or if response.session was set, save 63 64 # those changes and set a session cookie. 65 patch_vary_headers(response, ('Cookie',)) 64 66 try: 65 67 modified = request.session.modified django/branches/i18n/django/views/admin/main.py
r787 r815 252 252 lookup_val2 = request.GET.get(lookup_kwarg2, None) 253 253 filter_template.append('<h3>By %s:</h3><ul>\n' % f.verbose_name) 254 for k, v in (('All', None), ('Yes', ' True'), ('No', 'False')):254 for k, v in (('All', None), ('Yes', '1'), ('No', '0')): 255 255 filter_template.append('<li%s><a href="%s">%s</a></li>\n' % \ 256 256 (((lookup_val == v and not lookup_val2) and ' class="selected"' or ''), django/branches/i18n/django/views/decorators/cache.py
r787 r815 1 from django.core.cache import cache 2 from django.utils.httpwrappers import HttpResponseNotModified 3 from django.utils.text import compress_string 4 from django.conf.settings import DEFAULT_CHARSET 5 import datetime, md5 1 """ 2 Decorator for views that tries getting the page from the cache and 3 populates the cache if the page isn't in the cache yet. 6 4 7 def cache_page(view_func, cache_timeout, key_prefix=''): 8 """ 9 Decorator for views that tries getting the page from the cache and 10 populates the cache if the page isn't in the cache yet. Also takes care 11 of ETags and gzips the page if the client supports it. 5 The cache is keyed by the URL and some data from the headers. Additionally 6 there is the key prefix that is used to distinguish different cache areas 7 in a multi-site setup. You could use the sites.get_current().domain, for 8 example, as that is unique across a Django project. 12 9 13 The cache is keyed off of the page's URL plus the optional key_prefix 14 variable. Use key_prefix if your Django setup has multiple sites that 15 use cache; otherwise the cache for one site would affect the other. A good 16 example of key_prefix is to use sites.get_current().domain, because that's 17 unique across all Django instances on a particular server. 18 """ 19 def _check_cache(request, *args, **kwargs): 20 try: 21 accept_encoding = request.META['HTTP_ACCEPT_ENCODING'] 22 except KeyError: 23 accept_encoding = '' 24 accepts_gzip = 'gzip' in accept_encoding 25 cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % (key_prefix, request.path, accepts_gzip) 26 response = cache.get(cache_key, None) 27 if response is None: 28 response = view_func(request, *args, **kwargs) 29 content = response.get_content_as_string(DEFAULT_CHARSET) 30 if accepts_gzip: 31 content = compress_string(content) 32 response.content = content 33 response['Content-Encoding'] = 'gzip' 34 response['ETag'] = md5.new(content).hexdigest() 35 response['Content-Length'] = '%d' % len(content) 36 response['Last-Modified'] = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') 37 cache.set(cache_key, response, cache_timeout) 38 else: 39 # Logic is from http://simon.incutio.com/archive/2003/04/23/conditionalGet 40 try: 41 if_none_match = request.META['HTTP_IF_NONE_MATCH'] 42 except KeyError: 43 if_none_match = None 44 try: 45 if_modified_since = request.META['HTTP_IF_MODIFIED_SINCE'] 46 except KeyError: 47 if_modified_since = None 48 if if_none_match is None and if_modified_since is None: 49 pass 50 elif if_none_match is not None and response['ETag'] != if_none_match: 51 pass 52 elif if_modified_since is not None and response['Last-Modified'] != if_modified_since: 53 pass 54 else: 55 return HttpResponseNotModified() 56 return response 57 return _check_cache 10 Additionally, all headers from the response's Vary header will be taken into 11 account on caching -- just like the middleware does. 12 """ 13 14 from django.utils.decorators import decorator_from_middleware 15 from django.middleware.cache import CacheMiddleware 16 17 cache_page = decorator_from_middleware(CacheMiddleware) django/branches/i18n/docs/cache.txt
r705 r815 3 3 ======================== 4 4 5 So, you got slashdotted .Now what?5 So, you got slashdotted_. Now what? 6 6 7 7 Django's cache framework gives you three methods of caching dynamic pages in … … 10 10 entire site. 11 11 12 .. _slashdotted: http://en.wikipedia.org/wiki/Slashdot_effect 13 12 14 Setting up the cache 13 15 ==================== 14 16 15 The cache framework is split into a set of "backends" that provide different16 methods of caching data. There's a simple single-process memory cache (mostly 17 useful as a fallback) and a memcached_ backend (the fastest option, by far, if 18 you've gotthe RAM).17 The cache framework allows for different "backends" -- different methods of 18 caching data. There's a simple single-process memory cache (mostly useful as a 19 fallback) and a memcached_ backend (the fastest option, by far, if you've got 20 the RAM). 19 21 20 22 Before using the cache, you'll need to tell Django which cache backend you'd 21 23 like to use. Do this by setting the ``CACHE_BACKEND`` in your settings file. 22 24 23 The CACHE_BACKENDsetting is a "fake" URI (really an unregistered scheme).25 The ``CACHE_BACKEND`` setting is a "fake" URI (really an unregistered scheme). 24 26 Examples: 25 27 … … 40 42 probably don't want to use this except for 41 43 testing. Note that this cache backend is 42 NOT thread safe!44 NOT thread-safe! 43 45 44 46 locmem:/// A more sophisticated local memory cache; … … 73 75 arguments. 74 76 77 .. _memcached: http://www.danga.com/memcached/ 78 75 79 The per-site cache 76 80 ================== 77 81 78 Once the cache is set up, the simplest way to use the cache is to simply79 cache your entire site. Just add ``django.middleware.cache.CacheMiddleware`` 80 to your``MIDDLEWARE_CLASSES`` setting, as in this example::82 Once the cache is set up, the simplest way to use the cache is to cache your 83 entire site. Just add ``django.middleware.cache.CacheMiddleware`` to your 84 ``MIDDLEWARE_CLASSES`` setting, as in this example:: 81 85 82 86 MIDDLEWARE_CLASSES = ( … … 85 89 ) 86 90 87 Make sure it's the first entry in ``MIDDLEWARE_CLASSES``. (The order of 88 ``MIDDLEWARE_CLASSES`` matters.)89 90 Then, add the following three required settings :91 (The order of ``MIDDLEWARE_CLASSES`` matters. See "Order of MIDDLEWARE_CLASSES" 92 below.) 93 94 Then, add the following three required settings to your Django settings file: 91 95 92 96 * ``CACHE_MIDDLEWARE_SECONDS`` -- The number of seconds each page should be … … 103 107 zipping, and the cache will hold more pages because each one is smaller. 104 108 105 Pages with GET or POST parameters won't be cached. 106 107 The cache middleware also makes a few more optimizations: 108 109 * Sets and deals with ``ETag`` headers. 110 * Sets the ``Content-Length`` header. 109 The cache middleware caches every page that doesn't have GET or POST 110 parameters. Additionally, ``CacheMiddleware`` automatically sets a few headers 111 in each ``HttpResponse``: 112 111 113 * Sets the ``Last-Modified`` header to the current date/time when a fresh 112 114 (uncached) version of the page is requested. 113 114 It doesn't matter where in the middleware stack you put the cache middleware. 115 * Sets the ``Expires`` header to the current date/time plus the defined 116 ``CACHE_MIDDLEWARE_SECONDS``. 117 * Sets the ``Cache-Control`` header to give a max age for the page -- again, 118 from the ``CACHE_MIDDLEWARE_SECONDS`` setting. 119 120 See the `middleware documentation`_ for more on middleware. 121 122 .. _`middleware documentation`: http://www.djangoproject.com/documentation/middleware/ 115 123 116 124 The per-page cache … … 135 143 ... 136 144 137 This will cache the result of that view for 15 minutes. (The cache timeout is 138 in seconds.) 145 ``cache_page`` takes a single argument: the cache timeout, in seconds. In the 146 above example, the result of the ``slashdot_this()`` view will be cached for 15 147 minutes. 139 148 140 149 The low-level cache API 141 150 ======================= 142 151 143 There are times, however, that caching an entire rendered page doesn't gain 144 you very much. The Django developers have found it's only necessary to cache a 145 list of object IDs from an intensive database query, for example. In cases like 146 these, you can use the cache API to store objects in the cache with any level 147 of granularity you like. 152 Sometimes, however, caching an entire rendered page doesn't gain you very much. 153 For example, you may find it's only necessary to cache the result of an 154 intensive database. In cases like this, you can use the low-level cache API to 155 store objects in the cache with any level of granularity you like. 148 156 149 157 The cache API is simple:: 150 158 151 # the cache module exports a cache object that's automatically152 # created from the CACHE_BACKEND setting 159 # The cache module exports a cache object that's automatically 160 # created from the CACHE_BACKEND setting. 153 161 >>> from django.core.cache import cache 154 162 155 # The basic interface is set(key, value, timeout_seconds) and get(key) 163 # The basic interface is set(key, value, timeout_seconds) and get(key). 156 164 >>> cache.set('my_key', 'hello, world!', 30) 157 165 >>> cache.get('my_key') … … 162 170 None 163 171 164 # get() can take a default argument 172 # get() can take a default argument. 165 173 >>> cache.get('my_key', 'has_expired') 166 174 'has_expired' … … 184 192 can be pickled safely, although keys must be strings. 185 193 186 .. _memcached: http://www.danga.com/memcached/ 194 Controlling cache: Using Vary headers 195 ===================================== 196 197 The Django cache framework works with `HTTP Vary headers`_ to allow developers 198 to instruct caching mechanisms to differ their cache contents depending on 199 request HTTP headers. 200 201 Essentially, the ``Vary`` response HTTP header defines which request headers a 202 cache mechanism should take into account when building its cache key. 203 204 By default, Django's cache system creates its cache keys using the requested 205 path -- e.g., ``"/stories/2005/jun/23/bank_robbed/"``. This means every request 206 to that URL will use the same cached version, regardless of user-agent 207 differences such as cookies or language preferences. 208 209 That's where ``Vary`` comes in. 210 211 If your Django-powered page outputs different content based on some difference 212 in request headers -- such as a cookie, or language, or user-agent -- you'll 213 need to use the ``Vary`` header to tell caching mechanisms that the page output 214 depends on those things. 215 216 To do this in Django, use the convenient ``vary_on_headers`` view decorator, 217 like so:: 218 219 from django.views.decorators.vary import vary_on_headers 220 221 # Python 2.3 syntax. 222 def my_view(request): 223 ... 224 my_view = vary_on_headers(my_view, 'User-Agent') 225 226 # Python 2.4 decorator syntax. 227 @vary_on_headers('User-Agent') 228 def my_view(request): 229 ... 230 231 In this case, a caching mechanism (such as Django's own cache middleware) will 232 cache a separate version of the page for each unique user-agent. 233 234 The advantage to using the ``vary_on_headers`` decorator rather than manually 235 setting the ``Vary`` header (using something like 236 ``response['Vary'] = 'user-agent'``) is that the decorator adds to the ``Vary`` 237 header (which may already exist) rather than setting it from scratch. 238 239 Note that you can pass multiple headers to ``vary_on_headers()``:: 240 241 @vary_on_headers('User-Agent', 'Cookie') 242 def my_view(request): 243 ... 244 245 Because varying on cookie is such a common case, there's a ``vary_on_cookie`` 246 decorator. These two views are equivalent:: 247 248 @vary_on_cookie 249 def my_view(request): 250 ... 251 252 @vary_on_headers('Cookie') 253 def my_view(request): 254 ... 255 256 Also note that the headers you pass to ``vary_on_headers`` are not case 257 sensitive. ``"User-Agent"`` is the same thing as ``"user-agent"``. 258 259 You can also use a helper function, ``patch_vary_headers()``, directly:: 260 261 from django.utils.cache import patch_vary_headers 262 def my_view(request): 263 ... 264 response = render_to_response('template_name', context) 265 patch_vary_headers(response, ['Cookie']) 266 return response 267 268 ``patch_vary_headers`` takes an ``HttpResponse`` instance as its first argument 269 and a list/tuple of header names as its second argument. 270 271 .. _`HTTP Vary headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 272 273 Other optimizations 274 =================== 275 276 Django comes with a few other pieces of middleware that can help optimize your 277 apps' performance: 278 279 * ``django.middleware.http.ConditionalGetMiddleware`` adds support for 280 conditional GET. This makes use of ``ETag`` and ``Last-Modified`` 281 headers. 282 283 * ``django.middleware.gzip.GZipMiddleware`` compresses content for browsers 284 that understand gzip compression (all modern browsers). 285 286 Order of MIDDLEWARE_CLASSES 287 =========================== 288 289 If you use ``CacheMiddleware``, it's important to put it in the right place 290 within the ``MIDDLEWARE_CLASSES`` setting, because the cache middleware needs 291 to know which headers by which to vary the cache storage. Middleware always 292 adds something the ``Vary`` response header when it can. 293 294 Put the ``CacheMiddleware`` after any middlewares that might add something to 295 the ``Vary`` header. The following middlewares do so: 296 297 * ``SessionMiddleware`` adds ``Cookie`` 298 * ``GZipMiddleware`` adds ``Accept-Encoding`` django/branches/i18n/docs/django-admin.txt
r692 r815 184 184 185 185 --settings 186 ========== 186 ---------- 187 187 188 188 Example usage:: … … 194 194 ``django-admin.py`` will use the DJANGO_SETTINGS_MODULE environment variable. 195 195 196 --pythonpath 197 ------------ 198 199 Example usage:: 200 201 django-admin.py init --pythonpath='/home/djangoprojects/myproject' 202 203 Adds the given filesystem path to the Python `import search path`_. If this 204 isn't provided, ``django-admin.py`` will use the ``PYTHONPATH`` environment 205 variable. 206 207 .. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html 208 196 209 --help 197 ====== 210 ------ 198 211 199 212 Displays a help message that includes a terse list of all available actions and django/branches/i18n/docs/middleware.txt
r585 r815 46 46 ==================== 47 47 48 ``django.middleware.admin.AdminUserRequired`` 49 Limits site access to valid users with the ``is_staff`` flag set. This is 50 required by Django's admin, and this middleware requires ``SessionMiddleware``. 48 django.middleware.admin.AdminUserRequired 49 ----------------------------------------- 51 50 52 ``django.middleware.cache.CacheMiddleware`` 53 Enables site-wide cache. If this is enabled, each Django-powered page will be 54 cached for as long as the ``CACHE_MIDDLEWARE_SECONDS`` setting defines. See 55 the `cache documentation`_. 51 Limits site access to valid users with the ``is_staff`` flag set. This is 52 required by Django's admin, and this middleware requires ``SessionMiddleware``. 56 53 57 .. _`cache documentation`: http://www.djangoproject.com/documentation/cache/#the-per-site-cache 54 django.middleware.cache.CacheMiddleware 55 --------------------------------------- 58 56 59 ``django.middleware.common.CommonMiddleware`` 60 Adds a few conveniences for perfectionists: 57 Enables site-wide cache. If this is enabled, each Django-powered page will be 58 cached for as long as the ``CACHE_MIDDLEWARE_SECONDS`` setting defines. See 59 the `cache documentation`_. 61 60 62 * Forbids access to user agents in the ``DISALLOWED_USER_AGENTS`` setting, 63 which should be a list of strings. 61 .. _`cache documentation`: http://www.djangoproject.com/documentation/cache/#the-per-site-cache 64 62 65 * Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW`` 66 settings. If ``APPEND_SLASH`` is ``True``, URLs that lack a trailing 67 slash will be redirected to the same URL with a trailing slash. If 68 ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be 69 redirected to the same URL with a leading "www." 63 django.middleware.common.CommonMiddleware 64 ----------------------------------------- 70 65 71 Both of these options are meant to normalize URLs. The philosophy is that 72 each URL should exist in one, and only one, place. Technically a URL 73 ``foo.com/bar`` is distinct from ``foo.com/bar/`` -- a search-engine 74 indexer would treat them as separate URLs -- so it's best practice to 75 normalize URLs. 66 Adds a few conveniences for perfectionists: 76 67 77 * Handles ETags based on the ``USE_ETAGS`` setting. If ``USE_ETAGS`` is set 78 to ``True``, Django will calculate an ETag for each request by 79 MD5-hashing the page content, and it'll take care of sending 80 ``Not Modified`` responses, if appropriate. 68 * Forbids access to user agents in the ``DISALLOWED_USER_AGENTS`` setting, 69 which should be a list of strings. 81 70 82 * Handles flat pages. Every time Django encounters a 404 -- either within 83 a view or as a result of no URLconfs matching -- it will check the 84 database of flat pages based on the current URL. 71 * Performs URL rewriting based on the ``APPEND_SLASH`` and ``PREPEND_WWW`` 72 settings. If ``APPEND_SLASH`` is ``True``, URLs that lack a trailing 73 slash will be redirected to the same URL with a trailing slash. If 74 ``PREPEND_WWW`` is ``True``, URLs that lack a leading "www." will be 75 redirected to the same URL with a leading "www." 85 76 86 ``django.middleware.doc.XViewMiddleware`` 87 Sends custom ``X-View`` HTTP headers to HEAD requests that come from IP 88 addresses defined in the ``INTERNAL_IPS`` setting. This is used by Django's 89 automatic documentation system. 77 Both of these options are meant to normalize URLs. The philosophy is that 78 each URL should exist in one, and only one, place. Technically a URL 79 ``foo.com/bar`` is distinct from ``foo.com/bar/`` -- a search-engine 80 indexer would treat them as separate URLs -- so it's best practice to 81 normalize URLs. 90 82 91 ``django.middleware.sessions.SessionMiddleware`` 92 Enables session support. See the `session documentation`_. 83 * Handles ETags based on the ``USE_ETAGS`` setting. If ``USE_ETAGS`` is set 84 to ``True``, Django will calculate an ETag for each request by 85 MD5-hashing the page content, and it'll take care of sending 86 ``Not Modified`` responses, if appropriate. 93 87 94 .. _`session documentation`: http://www.djangoproject.com/documentation/sessions/ 88 * Handles flat pages. Every time Django encounters a 404 -- either within 89 a view or as a result of no URLconfs matching -- it will check the 90 database of flat pages based on the current URL. 91 92 django.middleware.doc.XViewMiddleware 93 ------------------------------------- 94 95 Sends custom ``X-View`` HTTP headers to HEAD requests that come from IP 96 addresses defined in the ``INTERNAL_IPS`` setting. This is used by Django's 97 automatic documentation system. 98 99 django.middleware.gzip.GZipMiddleware 100 ------------------------------------- 101 102 Compresses content for browsers that understand gzip compression (all modern 103 browsers). 104 105 django.middleware.http.ConditionalGetMiddleware 106 ----------------------------------------------- 107 108 Handles conditional GET operations. If the response has a ``ETag`` or 109 ``Last-Modified`` header, and the request has ``If-None-Match`` or 110 ``If-Modified-Since``, the response is replaced by an HttpNotModified. 111 112 Also removes the content from any response to a HEAD request and sets the 113 ``Date`` and ``Content-Length`` response-headers. 114 115 django.middleware.sessions.SessionMiddleware 116 -------------------------------------------- 117 118 Enables session support. See the `session documentation`_. 119 120 .. _`session documentation`: http://www.djangoproject.com/documentation/sessions/ 95 121 96 122 Writing your own middleware django/branches/i18n/tests/runtests.py
r646 r815 95 95 cursor = db.cursor() 96 96 try: 97 db.connection.autocommit( )97 db.connection.autocommit(1) 98 98 except AttributeError: 99 99 pass … … 181 181 self.output(1, "Deleting test database") 182 182 try: 183 db.connection.autocommit( )183 db.connection.autocommit(1) 184 184 except AttributeError: 185 185 pass
