diff --git a/django/conf/admin_media/css/global.css b/django/conf/admin_media/css/global.css index 31156589e0..7c60bf9755 100644 --- a/django/conf/admin_media/css/global.css +++ b/django/conf/admin_media/css/global.css @@ -230,6 +230,7 @@ fieldset.collapsed h2, fieldset.collapsed { display:block !important; } fieldset.collapsed .collapse-toggle { display: inline !important; } fieldset.collapse h2 a.collapse-toggle { color:#ffc; } fieldset.collapse h2 a.collapse-toggle:hover { text-decoration:underline; } +.hidden { display:none; } /* MESSAGES & ERRORS */ @@ -348,7 +349,7 @@ p.file-upload { line-height:20px; margin:0; padding:0; color:#666; font-size:11p ul.timelist, .timelist li { list-style-type:none; margin:0; padding:0; } .timelist a { padding:2px; } -/* OLD ORDERING WIDGET */ +/* ORDERING WIDGET */ ul#orderthese { padding:0; margin:0; list-style-type:none; } ul#orderthese li { list-style-type:none; display:block; padding:0; margin:6px 0; width:214px; background:#f6f6f6; white-space:nowrap; overflow:hidden; } diff --git a/django/core/cache.py b/django/core/cache.py index cbf02f2f3b..6391304158 100644 --- a/django/core/cache.py +++ b/django/core/cache.py @@ -15,7 +15,7 @@ The CACHE_BACKEND setting is a quasi-URI; examples are: memcached://127.0.0.1:11211/ A memcached backend; the server is running on localhost port 11211. - db://tablename/ A database backend in a table named + db://tablename/ A database backend in a table named "tablename". This table should be created with "django-admin createcachetable". @@ -26,7 +26,7 @@ The CACHE_BACKEND setting is a quasi-URI; examples are: probably don't want to use this except for testing. Note that this cache backend is NOT threadsafe! - + locmem:/// A more sophisticaed local memory cache; this is multi-process- and thread-safe. @@ -72,7 +72,6 @@ class InvalidCacheBackendError(Exception): ################################ class _Cache: - def __init__(self, params): timeout = params.get('timeout', 300) try: @@ -132,8 +131,7 @@ except ImportError: _MemcachedCache = None else: class _MemcachedCache(_Cache): - """Memcached cache backend.""" - + "Memcached cache backend." def __init__(self, server, params): _Cache.__init__(self, params) self._cache = memcache.Client([server]) @@ -161,8 +159,7 @@ else: import time class _SimpleCache(_Cache): - """Simple single-process in-memory cache""" - + "Simple single-process in-memory cache." def __init__(self, host, params): _Cache.__init__(self, params) self._cache = {} @@ -230,11 +227,11 @@ try: import cPickle as pickle except ImportError: import pickle +import copy from django.utils.synch import RWLock class _LocMemCache(_SimpleCache): - """Thread-safe in-memory cache""" - + "Thread-safe in-memory cache." def __init__(self, host, params): _SimpleCache.__init__(self, host, params) self._lock = RWLock() @@ -250,7 +247,7 @@ class _LocMemCache(_SimpleCache): elif exp < now: should_delete = True else: - return self._cache[key] + return copy.deepcopy(self._cache[key]) finally: self._lock.reader_leaves() if should_delete: @@ -261,14 +258,14 @@ class _LocMemCache(_SimpleCache): return default finally: self._lock.writer_leaves() - + def set(self, key, value, timeout=None): self._lock.writer_enters() try: _SimpleCache.set(self, key, value, timeout) finally: self._lock.writer_leaves() - + def delete(self, key): self._lock.writer_enters() try: @@ -284,8 +281,7 @@ import os import urllib class _FileCache(_SimpleCache): - """File-based cache""" - + "File-based cache." def __init__(self, dir, params): self._dir = dir if not os.path.exists(self._dir): @@ -293,7 +289,7 @@ class _FileCache(_SimpleCache): _SimpleCache.__init__(self, dir, params) del self._cache del self._expire_info - + def get(self, key, default=None): fname = self._key_to_file(key) try: @@ -308,7 +304,7 @@ class _FileCache(_SimpleCache): except (IOError, pickle.PickleError): pass return default - + def set(self, key, value, timeout=None): fname = self._key_to_file(key) if timeout is None: @@ -327,16 +323,16 @@ class _FileCache(_SimpleCache): pickle.dump(value, f, 2) except (IOError, OSError): raise - + def delete(self, key): try: os.remove(self._key_to_file(key)) except (IOError, OSError): pass - + def has_key(self, key): return os.path.exists(self._key_to_file(key)) - + def _cull(self, filelist): if self.cull_frequency == 0: doomed = filelist @@ -348,7 +344,7 @@ class _FileCache(_SimpleCache): except (IOError, OSError): pass - def _createdir(self): + def _createdir(self): try: os.makedirs(self._dir) except OSError: @@ -366,22 +362,21 @@ from django.core.db import db, DatabaseError from datetime import datetime class _DBCache(_Cache): - """SQL cache backend""" - + "SQL cache backend." def __init__(self, table, params): _Cache.__init__(self, params) self._table = table - max_entries = params.get('max_entries', 300) - try: - self._max_entries = int(max_entries) - except (ValueError, TypeError): - self._max_entries = 300 - cull_frequency = params.get('cull_frequency', 3) - try: - self._cull_frequency = int(cull_frequency) - except (ValueError, TypeError): - self._cull_frequency = 3 - + max_entries = params.get('max_entries', 300) + try: + self._max_entries = int(max_entries) + except (ValueError, TypeError): + self._max_entries = 300 + cull_frequency = params.get('cull_frequency', 3) + try: + self._cull_frequency = int(cull_frequency) + except (ValueError, TypeError): + self._cull_frequency = 3 + def get(self, key, default=None): cursor = db.cursor() cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key]) @@ -394,7 +389,7 @@ class _DBCache(_Cache): db.commit() return default return pickle.loads(base64.decodestring(row[1])) - + def set(self, key, value, timeout=None): if timeout is None: timeout = self.default_timeout @@ -417,17 +412,17 @@ class _DBCache(_Cache): pass else: db.commit() - + def delete(self, key): cursor = db.cursor() cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key]) db.commit() - + def has_key(self, key): cursor = db.cursor() cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s" % self._table, [key]) return cursor.fetchone() is not None - + def _cull(self, cursor, now): if self._cull_frequency == 0: cursor.execute("DELETE FROM %s" % self._table) @@ -438,7 +433,7 @@ class _DBCache(_Cache): if num > self._max_entries: cursor.execute("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % self._table, [num / self._cull_frequency]) cursor.execute("DELETE FROM %s WHERE cache_key < %%s" % self._table, [cursor.fetchone()[0]]) - + ########################################## # Read settings and load a cache backend # ########################################## diff --git a/django/core/management.py b/django/core/management.py index afb498ae63..046031e311 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -144,6 +144,10 @@ def get_sql_delete(mod): for row in cursor.fetchall(): output.append("DELETE FROM auth_admin_log WHERE content_type_id = %s;" % row[0]) + # Close database connection explicitly, in case this output is being piped + # directly into a database client, to avoid locking issues. + db.db.close() + return output[::-1] # Reverse it, to deal with table dependencies. get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given model module name(s)." get_sql_delete.args = APP_ARGS diff --git a/django/middleware/cache.py b/django/middleware/cache.py index 8216c40ae1..04f98122f7 100644 --- a/django/middleware/cache.py +++ b/django/middleware/cache.py @@ -1,4 +1,3 @@ -import copy from django.conf import settings from django.core.cache import cache from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers @@ -49,7 +48,7 @@ class CacheMiddleware: return None # No cache information available, need to rebuild. request._cache_update_cache = False - return copy.copy(response) + return response def process_response(self, request, response): "Sets the cache, if needed." diff --git a/django/utils/decorators.py b/django/utils/decorators.py index b21a4e4248..1333f9da88 100644 --- a/django/utils/decorators.py +++ b/django/utils/decorators.py @@ -12,6 +12,10 @@ def decorator_from_middleware(middleware_class): result = middleware.process_request(request) if result is not None: return result + if hasattr(middleware, 'process_view'): + result = middleware.process_view(request, view_func, **kwargs) + if result is not None: + return result response = view_func(request, *args, **kwargs) if hasattr(middleware, 'process_response'): result = middleware.process_response(request, response) diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py index 6328b7097a..f4cdf90c56 100644 --- a/django/views/generic/list_detail.py +++ b/django/views/generic/list_detail.py @@ -32,6 +32,8 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F the previous page pages number of pages, total + hits + number of objects, total """ mod = models.get_module(app_label, module_name) lookup_kwargs = extra_lookup_kwargs.copy() @@ -56,6 +58,7 @@ def object_list(request, app_label, module_name, paginate_by=None, allow_empty=F 'next': page + 1, 'previous': page - 1, 'pages': paginator.pages, + 'hits' : paginator.hits, }) else: object_list = mod.get_list(**lookup_kwargs) diff --git a/docs/db-api.txt b/docs/db-api.txt index 8a02437aaa..b80d4e8647 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -449,8 +449,7 @@ Related objects (e.g. ``Choices``) are created using convenience functions:: >>> p.get_choice_count() 4 -Each of those ``add_choice`` methods is equivalent to (except obviously much -simpler than):: +Each of those ``add_choice`` methods is equivalent to (but much simpler than):: >>> c = polls.Choice(poll_id=p.id, choice="Over easy", votes=0) >>> c.save() @@ -459,6 +458,8 @@ Note that when using the `add_foo()`` methods, you do not give any value for the ``id`` field, nor do you give a value for the field that stores the relation (``poll_id`` in this case). +The ``add_FOO()`` method always returns the newly created object. + Deleting objects ================ diff --git a/docs/generic_views.txt b/docs/generic_views.txt index 62e7c14e2b..1c0de07a7a 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -115,7 +115,7 @@ The date-based generic functions are: Yearly archive. Requires that the ``year`` argument be present in the URL pattern. - Uses the template ``app_label/module_name__archive_year`` by default. + Uses the template ``app_label/module_name_archive_year`` by default. Has the following template context: @@ -134,7 +134,7 @@ The date-based generic functions are: default, which is a three-letter month abbreviation. To change it to use numbers, use ``"%m"``. - Uses the template ``app_label/module_name__archive_month`` by default. + Uses the template ``app_label/module_name_archive_month`` by default. Has the following template context: @@ -151,7 +151,7 @@ The date-based generic functions are: also pass ``day_format``, which defaults to ``"%d"`` (day of the month as a decimal number, 1-31). - Uses the template ``app_label/module_name__archive_day`` by default. + Uses the template ``app_label/module_name_archive_day`` by default. Has the following template context: @@ -246,6 +246,8 @@ Individual views are: The previous page ``pages`` Number of pages total + ``hits`` + Total number of objects ``object_detail`` Object detail page. This works like and takes the same arguments as @@ -272,7 +274,7 @@ The create/update/delete views are: be interpolated against the object's field attributes. For example, you could use ``post_save_redirect="/polls/%(slug)s/"``. - Uses the template ``app_label/module_name__form`` by default. This is the + Uses the template ``app_label/module_name_form`` by default. This is the same template as the ``update_object`` view below. Your template can tell the different by the presence or absence of ``{{ object }}`` in the context. @@ -294,7 +296,7 @@ The create/update/delete views are: ``list_detail.object_detail`` does (see above), and the same ``post_save_redirect`` as ``create_object`` does. - Uses the template ``app_label/module_name__form`` by default. + Uses the template ``app_label/module_name_form`` by default. Has the following template context: diff --git a/docs/model-api.txt b/docs/model-api.txt index 4af193ca48..2ad2b3594d 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -95,8 +95,8 @@ The following arguments are available to all field types. All are optional. ('GR', 'Graduate'), ) - The first element in each tuple is the actual value to be stored. The - second element is the human-readable name for the option. + The first element in each tuple is the actual value to be stored. The + second element is the human-readable name for the option. ``core`` For objects that are edited inline to a related object. @@ -248,18 +248,18 @@ Here are all available field types: uploaded files don't fill up the given directory). The admin represents this as an ```` (a file-upload widget). - - Using a `FieldField` or an ``ImageField`` (see below) in a model takes a few + + Using a `FieldField` or an ``ImageField`` (see below) in a model takes a few steps: - + 1. In your settings file, you'll need to define ``MEDIA_ROOT``as the full path to a directory where you'd like Django to store uploaded files. (For performance, these files are not stored in the database.) Define ``MEDIA_URL`` as the base public URL of that directory. Make sure that this directory is writable by the Web server's user account. - - 2. Add the ``FileField`` or ``ImageField`` to your model, making sure + + 2. Add the ``FileField`` or ``ImageField`` to your model, making sure to define the ``upload_to`` option to tell Django to which subdirectory of ``MEDIA_ROOT`` it should upload files. @@ -269,7 +269,7 @@ Here are all available field types: example, if your ``ImageField`` is called ``mug_shot``, you can get the absolute URL to your image in a template with ``{{ object.get_mug_shot_url }}``. - + .. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941 ``FloatField`` @@ -302,7 +302,7 @@ Here are all available field types: width of the image each time a model instance is saved. Requires the `Python Imaging Library`_. - + .. _Python Imaging Library: http://www.pythonware.com/products/pil/ ``IntegerField`` @@ -721,7 +721,9 @@ Here's a list of all possible ``META`` options. No options are required. Adding unique_together = (("driver", "restaurant"),) This is a list of lists of fields that must be unique when considered - together. It's used in the Django admin. + together. It's used in the Django admin and is enforced at the database + level (i.e., the appropriate ``UNIQUE`` statements are included in the + ``CREATE TABLE`` statement). ``verbose_name`` A human-readable name for the object, singular::