summaryrefslogtreecommitdiff
path: root/django/core
diff options
context:
space:
mode:
authorArthur Koziel <arthur@arthurkoziel.com>2010-09-13 00:04:27 +0000
committerArthur Koziel <arthur@arthurkoziel.com>2010-09-13 00:04:27 +0000
commitdd49269c7db008b2567f50cb03c4d3d9b321daa1 (patch)
tree326dd25bb045ac016cda7966b43cbdfe1f67d699 /django/core
parentc9b188c4ec939abbe48dae5a371276742e64b6b8 (diff)
downloaddjango-soc2010/app-loading.tar.gz
[soc2010/app-loading] merged trunkarchive/soc2010/app-loadingsoc2010/app-loading
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/app-loading@13818 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/core')
-rw-r--r--django/core/cache/__init__.py2
-rw-r--r--django/core/cache/backends/base.py28
-rw-r--r--django/core/cache/backends/db.py105
-rw-r--r--django/core/cache/backends/dummy.py15
-rw-r--r--django/core/cache/backends/filebased.py7
-rw-r--r--django/core/cache/backends/locmem.py5
-rw-r--r--django/core/exceptions.py7
-rw-r--r--django/core/files/images.py19
-rw-r--r--django/core/handlers/base.py3
-rw-r--r--django/core/handlers/modpython.py4
-rw-r--r--django/core/management/__init__.py10
-rw-r--r--django/core/management/base.py24
-rw-r--r--django/core/management/commands/dumpdata.py43
-rw-r--r--django/core/management/commands/flush.py10
-rw-r--r--django/core/management/commands/loaddata.py71
-rw-r--r--django/core/management/commands/syncdb.py14
-rw-r--r--django/core/management/commands/testserver.py5
-rw-r--r--django/core/urlresolvers.py56
18 files changed, 309 insertions, 119 deletions
diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py
index 1b602908cb..680f724f94 100644
--- a/django/core/cache/__init__.py
+++ b/django/core/cache/__init__.py
@@ -18,7 +18,7 @@ See docs/cache.txt for information on the public API.
from cgi import parse_qsl
from django.conf import settings
from django.core import signals
-from django.core.cache.backends.base import InvalidCacheBackendError
+from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning
from django.utils import importlib
# Name for use in settings file --> name of module in "backends" directory.
diff --git a/django/core/cache/backends/base.py b/django/core/cache/backends/base.py
index e58267a2e9..83dd461804 100644
--- a/django/core/cache/backends/base.py
+++ b/django/core/cache/backends/base.py
@@ -1,10 +1,18 @@
"Base Cache class."
-from django.core.exceptions import ImproperlyConfigured
+import warnings
+
+from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
class InvalidCacheBackendError(ImproperlyConfigured):
pass
+class CacheKeyWarning(DjangoRuntimeWarning):
+ pass
+
+# Memcached does not accept keys longer than this.
+MEMCACHE_MAX_KEY_LENGTH = 250
+
class BaseCache(object):
def __init__(self, params):
timeout = params.get('timeout', 300)
@@ -116,3 +124,21 @@ class BaseCache(object):
def clear(self):
"""Remove *all* values from the cache at once."""
raise NotImplementedError
+
+ def validate_key(self, key):
+ """
+ Warn about keys that would not be portable to the memcached
+ backend. This encourages (but does not force) writing backend-portable
+ cache code.
+
+ """
+ if len(key) > MEMCACHE_MAX_KEY_LENGTH:
+ warnings.warn('Cache key will cause errors if used with memcached: '
+ '%s (longer than %s)' % (key, MEMCACHE_MAX_KEY_LENGTH),
+ CacheKeyWarning)
+ for char in key:
+ if ord(char) < 33 or ord(char) == 127:
+ warnings.warn('Cache key contains characters that will cause '
+ 'errors if used with memcached: %r' % key,
+ CacheKeyWarning)
+
diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py
index 3398e6a85b..c4429c80b3 100644
--- a/django/core/cache/backends/db.py
+++ b/django/core/cache/backends/db.py
@@ -1,7 +1,7 @@
"Database cache backend."
from django.core.cache.backends.base import BaseCache
-from django.db import connection, transaction, DatabaseError
+from django.db import connections, router, transaction, DatabaseError
import base64, time
from datetime import datetime
try:
@@ -9,10 +9,31 @@ try:
except ImportError:
import pickle
+class Options(object):
+ """A class that will quack like a Django model _meta class.
+
+ This allows cache operations to be controlled by the router
+ """
+ def __init__(self, table):
+ self.db_table = table
+ self.app_label = 'django_cache'
+ self.module_name = 'cacheentry'
+ self.verbose_name = 'cache entry'
+ self.verbose_name_plural = 'cache entries'
+ self.object_name = 'CacheEntry'
+ self.abstract = False
+ self.managed = True
+ self.proxy = False
+
class CacheClass(BaseCache):
def __init__(self, table, params):
BaseCache.__init__(self, params)
- self._table = connection.ops.quote_name(table)
+ self._table = table
+
+ class CacheEntry(object):
+ _meta = Options(table)
+ self.cache_model_class = CacheEntry
+
max_entries = params.get('max_entries', 300)
try:
self._max_entries = int(max_entries)
@@ -25,78 +46,100 @@ class CacheClass(BaseCache):
self._cull_frequency = 3
def get(self, key, default=None):
- cursor = connection.cursor()
- cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
+ self.validate_key(key)
+ db = router.db_for_read(self.cache_model_class)
+ table = connections[db].ops.quote_name(self._table)
+ cursor = connections[db].cursor()
+
+ cursor.execute("SELECT cache_key, value, expires FROM %s WHERE cache_key = %%s" % table, [key])
row = cursor.fetchone()
if row is None:
return default
now = datetime.now()
if row[2] < now:
- cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key])
- transaction.commit_unless_managed()
+ db = router.db_for_write(self.cache_model_class)
+ cursor = connections[db].cursor()
+ cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key])
+ transaction.commit_unless_managed(using=db)
return default
- value = connection.ops.process_clob(row[1])
+ value = connections[db].ops.process_clob(row[1])
return pickle.loads(base64.decodestring(value))
def set(self, key, value, timeout=None):
+ self.validate_key(key)
self._base_set('set', key, value, timeout)
def add(self, key, value, timeout=None):
+ self.validate_key(key)
return self._base_set('add', key, value, timeout)
def _base_set(self, mode, key, value, timeout=None):
if timeout is None:
timeout = self.default_timeout
- cursor = connection.cursor()
- cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
+ db = router.db_for_write(self.cache_model_class)
+ table = connections[db].ops.quote_name(self._table)
+ cursor = connections[db].cursor()
+
+ cursor.execute("SELECT COUNT(*) FROM %s" % table)
num = cursor.fetchone()[0]
now = datetime.now().replace(microsecond=0)
exp = datetime.fromtimestamp(time.time() + timeout).replace(microsecond=0)
if num > self._max_entries:
- self._cull(cursor, now)
+ self._cull(db, cursor, now)
encoded = base64.encodestring(pickle.dumps(value, 2)).strip()
- cursor.execute("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % self._table, [key])
+ cursor.execute("SELECT cache_key, expires FROM %s WHERE cache_key = %%s" % table, [key])
try:
result = cursor.fetchone()
if result and (mode == 'set' or
(mode == 'add' and result[1] < now)):
- cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % self._table,
- [encoded, connection.ops.value_to_db_datetime(exp), key])
+ cursor.execute("UPDATE %s SET value = %%s, expires = %%s WHERE cache_key = %%s" % table,
+ [encoded, connections[db].ops.value_to_db_datetime(exp), key])
else:
- cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % self._table,
- [key, encoded, connection.ops.value_to_db_datetime(exp)])
+ cursor.execute("INSERT INTO %s (cache_key, value, expires) VALUES (%%s, %%s, %%s)" % table,
+ [key, encoded, connections[db].ops.value_to_db_datetime(exp)])
except DatabaseError:
# To be threadsafe, updates/inserts are allowed to fail silently
- transaction.rollback_unless_managed()
+ transaction.rollback_unless_managed(using=db)
return False
else:
- transaction.commit_unless_managed()
+ transaction.commit_unless_managed(using=db)
return True
def delete(self, key):
- cursor = connection.cursor()
- cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % self._table, [key])
- transaction.commit_unless_managed()
+ self.validate_key(key)
+ db = router.db_for_write(self.cache_model_class)
+ table = connections[db].ops.quote_name(self._table)
+ cursor = connections[db].cursor()
+
+ cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key])
+ transaction.commit_unless_managed(using=db)
def has_key(self, key):
+ self.validate_key(key)
+ db = router.db_for_read(self.cache_model_class)
+ table = connections[db].ops.quote_name(self._table)
+ cursor = connections[db].cursor()
+
now = datetime.now().replace(microsecond=0)
- cursor = connection.cursor()
- cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % self._table,
- [key, connection.ops.value_to_db_datetime(now)])
+ cursor.execute("SELECT cache_key FROM %s WHERE cache_key = %%s and expires > %%s" % table,
+ [key, connections[db].ops.value_to_db_datetime(now)])
return cursor.fetchone() is not None
- def _cull(self, cursor, now):
+ def _cull(self, db, cursor, now):
if self._cull_frequency == 0:
self.clear()
else:
- cursor.execute("DELETE FROM %s WHERE expires < %%s" % self._table,
- [connection.ops.value_to_db_datetime(now)])
- cursor.execute("SELECT COUNT(*) FROM %s" % self._table)
+ table = connections[db].ops.quote_name(self._table)
+ cursor.execute("DELETE FROM %s WHERE expires < %%s" % table,
+ [connections[db].ops.value_to_db_datetime(now)])
+ cursor.execute("SELECT COUNT(*) FROM %s" % table)
num = cursor.fetchone()[0]
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]])
+ cursor.execute("SELECT cache_key FROM %s ORDER BY cache_key LIMIT 1 OFFSET %%s" % table, [num / self._cull_frequency])
+ cursor.execute("DELETE FROM %s WHERE cache_key < %%s" % table, [cursor.fetchone()[0]])
def clear(self):
- cursor = connection.cursor()
- cursor.execute('DELETE FROM %s' % self._table)
+ db = router.db_for_write(self.cache_model_class)
+ table = connections[db].ops.quote_name(self._table)
+ cursor = connections[db].cursor()
+ cursor.execute('DELETE FROM %s' % table)
diff --git a/django/core/cache/backends/dummy.py b/django/core/cache/backends/dummy.py
index 4337484cb1..f73b7408bc 100644
--- a/django/core/cache/backends/dummy.py
+++ b/django/core/cache/backends/dummy.py
@@ -6,22 +6,25 @@ class CacheClass(BaseCache):
def __init__(self, *args, **kwargs):
pass
- def add(self, *args, **kwargs):
+ def add(self, key, *args, **kwargs):
+ self.validate_key(key)
return True
def get(self, key, default=None):
+ self.validate_key(key)
return default
- def set(self, *args, **kwargs):
- pass
+ def set(self, key, *args, **kwargs):
+ self.validate_key(key)
- def delete(self, *args, **kwargs):
- pass
+ def delete(self, key, *args, **kwargs):
+ self.validate_key(key)
def get_many(self, *args, **kwargs):
return {}
- def has_key(self, *args, **kwargs):
+ def has_key(self, key, *args, **kwargs):
+ self.validate_key(key)
return False
def set_many(self, *args, **kwargs):
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index fe833336d0..46e69f3091 100644
--- a/django/core/cache/backends/filebased.py
+++ b/django/core/cache/backends/filebased.py
@@ -32,6 +32,7 @@ class CacheClass(BaseCache):
self._createdir()
def add(self, key, value, timeout=None):
+ self.validate_key(key)
if self.has_key(key):
return False
@@ -39,6 +40,7 @@ class CacheClass(BaseCache):
return True
def get(self, key, default=None):
+ self.validate_key(key)
fname = self._key_to_file(key)
try:
f = open(fname, 'rb')
@@ -56,6 +58,7 @@ class CacheClass(BaseCache):
return default
def set(self, key, value, timeout=None):
+ self.validate_key(key)
fname = self._key_to_file(key)
dirname = os.path.dirname(fname)
@@ -79,6 +82,7 @@ class CacheClass(BaseCache):
pass
def delete(self, key):
+ self.validate_key(key)
try:
self._delete(self._key_to_file(key))
except (IOError, OSError):
@@ -95,6 +99,7 @@ class CacheClass(BaseCache):
pass
def has_key(self, key):
+ self.validate_key(key)
fname = self._key_to_file(key)
try:
f = open(fname, 'rb')
@@ -116,7 +121,7 @@ class CacheClass(BaseCache):
return
try:
- filelist = os.listdir(self._dir)
+ filelist = sorted(os.listdir(self._dir))
except (IOError, OSError):
return
diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py
index eff1201b97..fe33d33307 100644
--- a/django/core/cache/backends/locmem.py
+++ b/django/core/cache/backends/locmem.py
@@ -30,6 +30,7 @@ class CacheClass(BaseCache):
self._lock = RWLock()
def add(self, key, value, timeout=None):
+ self.validate_key(key)
self._lock.writer_enters()
try:
exp = self._expire_info.get(key)
@@ -44,6 +45,7 @@ class CacheClass(BaseCache):
self._lock.writer_leaves()
def get(self, key, default=None):
+ self.validate_key(key)
self._lock.reader_enters()
try:
exp = self._expire_info.get(key)
@@ -76,6 +78,7 @@ class CacheClass(BaseCache):
self._expire_info[key] = time.time() + timeout
def set(self, key, value, timeout=None):
+ self.validate_key(key)
self._lock.writer_enters()
# Python 2.4 doesn't allow combined try-except-finally blocks.
try:
@@ -87,6 +90,7 @@ class CacheClass(BaseCache):
self._lock.writer_leaves()
def has_key(self, key):
+ self.validate_key(key)
self._lock.reader_enters()
try:
exp = self._expire_info.get(key)
@@ -127,6 +131,7 @@ class CacheClass(BaseCache):
pass
def delete(self, key):
+ self.validate_key(key)
self._lock.writer_enters()
try:
self._delete(key)
diff --git a/django/core/exceptions.py b/django/core/exceptions.py
index ee6d5fe37b..21be8702fa 100644
--- a/django/core/exceptions.py
+++ b/django/core/exceptions.py
@@ -1,4 +1,9 @@
-"Global Django exceptions"
+"""
+Global Django exception and warning classes.
+"""
+
+class DjangoRuntimeWarning(RuntimeWarning):
+ pass
class ObjectDoesNotExist(Exception):
"The requested object does not exist"
diff --git a/django/core/files/images.py b/django/core/files/images.py
index 55008b548a..228a7118c5 100644
--- a/django/core/files/images.py
+++ b/django/core/files/images.py
@@ -23,23 +23,26 @@ class ImageFile(File):
if not hasattr(self, '_dimensions_cache'):
close = self.closed
self.open()
- self._dimensions_cache = get_image_dimensions(self)
- if close:
- self.close()
+ self._dimensions_cache = get_image_dimensions(self, close=close)
return self._dimensions_cache
-def get_image_dimensions(file_or_path):
- """Returns the (width, height) of an image, given an open file or a path."""
+def get_image_dimensions(file_or_path, close=False):
+ """
+ Returns the (width, height) of an image, given an open file or a path. Set
+ 'close' to True to close the file at the end if it is initially in an open
+ state.
+ """
# Try to import PIL in either of the two ways it can end up installed.
try:
from PIL import ImageFile as PILImageFile
except ImportError:
import ImageFile as PILImageFile
-
+
p = PILImageFile.Parser()
- close = False
if hasattr(file_or_path, 'read'):
file = file_or_path
+ file_pos = file.tell()
+ file.seek(0)
else:
file = open(file_or_path, 'rb')
close = True
@@ -55,3 +58,5 @@ def get_image_dimensions(file_or_path):
finally:
if close:
file.close()
+ else:
+ file.seek(file_pos)
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py
index 79f6607214..b03c2fd71e 100644
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -137,9 +137,8 @@ class BaseHandler(object):
raise
except: # Handle everything else, including SuspiciousOperation, etc.
# Get the exception info now, in case another exception is thrown later.
- exc_info = sys.exc_info()
receivers = signals.got_request_exception.send(sender=self.__class__, request=request)
- return self.handle_uncaught_exception(request, resolver, exc_info)
+ return self.handle_uncaught_exception(request, resolver, sys.exc_info())
finally:
# Reset URLconf for this thread on the way out for complete
# isolation of request.urlconf
diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py
index b1e3e17227..17e739600c 100644
--- a/django/core/handlers/modpython.py
+++ b/django/core/handlers/modpython.py
@@ -1,5 +1,6 @@
import os
from pprint import pformat
+from warnings import warn
from django import http
from django.core import signals
@@ -179,6 +180,9 @@ class ModPythonHandler(BaseHandler):
request_class = ModPythonRequest
def __call__(self, req):
+ warn(('The mod_python handler is deprecated; use a WSGI or FastCGI server instead.'),
+ PendingDeprecationWarning)
+
# mod_python fakes the environ, and thus doesn't process SetEnv. This fixes that
os.environ.update(req.subprocess_env)
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index a61b648674..dabde96377 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -250,15 +250,15 @@ class ManagementUtility(object):
"""
try:
app_name = get_commands()[subcommand]
- if isinstance(app_name, BaseCommand):
- # If the command is already loaded, use it directly.
- klass = app_name
- else:
- klass = load_command_class(app_name, subcommand)
except KeyError:
sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % \
(subcommand, self.prog_name))
sys.exit(1)
+ if isinstance(app_name, BaseCommand):
+ # If the command is already loaded, use it directly.
+ klass = app_name
+ else:
+ klass = load_command_class(app_name, subcommand)
return klass
def autocomplete(self):
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 4016faaa7a..dcd83ff300 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -118,7 +118,7 @@ class BaseCommand(object):
# Metadata about this command.
option_list = (
make_option('-v', '--verbosity', action='store', dest='verbosity', default='1',
- type='choice', choices=['0', '1', '2'],
+ type='choice', choices=['0', '1', '2', '3'],
help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
make_option('--settings',
help='The Python path to a settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.'),
@@ -213,20 +213,24 @@ class BaseCommand(object):
sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
sys.exit(1)
try:
+ self.stdout = options.get('stdout', sys.stdout)
+ self.stderr = options.get('stderr', sys.stderr)
if self.requires_model_validation:
self.validate()
output = self.handle(*args, **options)
if output:
if self.output_transaction:
- # This needs to be imported here, because it relies on settings.
- from django.db import connection
+ # This needs to be imported here, because it relies on
+ # settings.
+ from django.db import connections, DEFAULT_DB_ALIAS
+ connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
if connection.ops.start_transaction_sql():
- print self.style.SQL_KEYWORD(connection.ops.start_transaction_sql())
- print output
+ self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()))
+ self.stdout.write(output)
if self.output_transaction:
- print self.style.SQL_KEYWORD("COMMIT;")
+ self.stdout.write(self.style.SQL_KEYWORD("COMMIT;") + '\n')
except CommandError, e:
- sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
+ self.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
sys.exit(1)
def validate(self, app=None, display_num_errors=False):
@@ -248,7 +252,7 @@ class BaseCommand(object):
error_text = s.read()
raise CommandError("One or more models did not validate:\n%s" % error_text)
if display_num_errors:
- print "%s error%s found" % (num_errors, num_errors != 1 and 's' or '')
+ self.stdout.write("%s error%s found\n" % (num_errors, num_errors != 1 and 's' or ''))
def handle(self, *args, **options):
"""
@@ -390,9 +394,9 @@ def copy_helper(style, app_or_project, name, directory, other_name=''):
relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
if relative_dir:
os.mkdir(os.path.join(top_dir, relative_dir))
- for i, subdir in enumerate(subdirs):
+ for subdir in subdirs[:]:
if subdir.startswith('.'):
- del subdirs[i]
+ subdirs.remove(subdir)
for f in files:
if not f.endswith('.py'):
# Ignore .pyc, .pyo, .py.class etc, as they cause various
diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py
index aaaa5845a5..706bf601f9 100644
--- a/django/core/management/commands/dumpdata.py
+++ b/django/core/management/commands/dumpdata.py
@@ -16,11 +16,15 @@ class Command(BaseCommand):
default=DEFAULT_DB_ALIAS, help='Nominates a specific database to load '
'fixtures into. Defaults to the "default" database.'),
make_option('-e', '--exclude', dest='exclude',action='append', default=[],
- help='App to exclude (use multiple --exclude to exclude multiple apps).'),
+ help='An appname or appname.ModelName to exclude (use multiple --exclude to exclude multiple apps/models).'),
make_option('-n', '--natural', action='store_true', dest='use_natural_keys', default=False,
help='Use natural keys if they are available.'),
+ make_option('-a', '--all', action='store_true', dest='use_base_manager', default=False,
+ help="Use Django's base manager to dump all models stored in the database, including those that would otherwise be filtered or modified by a custom manager."),
)
- help = 'Output the contents of the database as a fixture of the given format.'
+ help = ("Output the contents of the database as a fixture of the given "
+ "format (using each model's default manager unless --all is "
+ "specified).")
args = '[appname appname.ModelName ...]'
def handle(self, *app_labels, **options):
@@ -30,11 +34,26 @@ class Command(BaseCommand):
indent = options.get('indent',None)
using = options.get('database', DEFAULT_DB_ALIAS)
connection = connections[using]
- exclude = options.get('exclude',[])
+ excludes = options.get('exclude',[])
show_traceback = options.get('traceback', False)
use_natural_keys = options.get('use_natural_keys', False)
-
- excluded_apps = set(get_app(app_label) for app_label in exclude)
+ use_base_manager = options.get('use_base_manager', False)
+
+ excluded_apps = set()
+ excluded_models = set()
+ for exclude in excludes:
+ if '.' in exclude:
+ app_label, model_name = exclude.split('.', 1)
+ model_obj = get_model(app_label, model_name)
+ if not model_obj:
+ raise CommandError('Unknown model in excludes: %s' % exclude)
+ excluded_models.add(model_obj)
+ else:
+ try:
+ app_obj = get_app(exclude)
+ excluded_apps.add(app_obj)
+ except ImproperlyConfigured:
+ raise CommandError('Unknown app in excludes: %s' % exclude)
if len(app_labels) == 0:
app_list = SortedDict((app, None) for app in get_apps() if app not in excluded_apps)
@@ -47,7 +66,8 @@ class Command(BaseCommand):
app = get_app(app_label)
except ImproperlyConfigured:
raise CommandError("Unknown application: %s" % app_label)
-
+ if app in excluded_apps:
+ continue
model = get_model(app_label, model_label)
if model is None:
raise CommandError("Unknown model: %s.%s" % (app_label, model_label))
@@ -64,6 +84,8 @@ class Command(BaseCommand):
app = get_app(app_label)
except ImproperlyConfigured:
raise CommandError("Unknown application: %s" % app_label)
+ if app in excluded_apps:
+ continue
app_list[app] = None
# Check that the serialization format exists; this is a shortcut to
@@ -79,8 +101,13 @@ class Command(BaseCommand):
# Now collate the objects to be serialized.
objects = []
for model in sort_dependencies(app_list.items()):
+ if model in excluded_models:
+ continue
if not model._meta.proxy and router.allow_syncdb(using, model):
- objects.extend(model._default_manager.using(using).all())
+ if use_base_manager:
+ objects.extend(model._base_manager.using(using).all())
+ else:
+ objects.extend(model._default_manager.using(using).all())
try:
return serializers.serialize(format, objects, indent=indent,
@@ -163,4 +190,4 @@ def sort_dependencies(app_list):
)
model_dependencies = skipped
- return model_list \ No newline at end of file
+ return model_list
diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py
index 6836fe35ca..093c6db7b9 100644
--- a/django/core/management/commands/flush.py
+++ b/django/core/management/commands/flush.py
@@ -1,7 +1,7 @@
from optparse import make_option
from django.conf import settings
-from django.db import connections, transaction, models, DEFAULT_DB_ALIAS
+from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
from django.core.management import call_command
from django.core.management.base import NoArgsCommand, CommandError
from django.core.management.color import no_style
@@ -66,7 +66,13 @@ The full error: %s""" % (connection.settings_dict['NAME'], e))
# Emit the post sync signal. This allows individual
# applications to respond as if the database had been
# sync'd from scratch.
- emit_post_sync_signal(models.get_models(), verbosity, interactive, db)
+ all_models = []
+ for app in models.get_apps():
+ all_models.extend([
+ m for m in models.get_models(app, include_auto_created=True)
+ if router.allow_syncdb(db, m)
+ ])
+ emit_post_sync_signal(set(all_models), verbosity, interactive, db)
# Reinstall the initial_data fixture.
kwargs = options.copy()
diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
index 6212d6151d..0b752b57e2 100644
--- a/django/core/management/commands/loaddata.py
+++ b/django/core/management/commands/loaddata.py
@@ -47,7 +47,8 @@ class Command(BaseCommand):
# Keep a count of the installed objects and fixtures
fixture_count = 0
- object_count = 0
+ loaded_object_count = 0
+ fixture_object_count = 0
models = set()
humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
@@ -111,11 +112,11 @@ class Command(BaseCommand):
formats = []
if formats:
- if verbosity > 1:
- print "Loading '%s' fixtures..." % fixture_name
+ if verbosity >= 2:
+ self.stdout.write("Loading '%s' fixtures...\n" % fixture_name)
else:
- sys.stderr.write(
- self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format." %
+ self.stderr.write(
+ self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format.\n" %
(fixture_name, format)))
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
@@ -127,8 +128,8 @@ class Command(BaseCommand):
fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + ['']
for fixture_dir in fixture_dirs:
- if verbosity > 1:
- print "Checking %s for fixtures..." % humanize(fixture_dir)
+ if verbosity >= 2:
+ self.stdout.write("Checking %s for fixtures...\n" % humanize(fixture_dir))
label_found = False
for combo in product([using, None], formats, compression_formats):
@@ -140,34 +141,37 @@ class Command(BaseCommand):
if p
)
- if verbosity > 1:
- print "Trying %s for %s fixture '%s'..." % \
- (humanize(fixture_dir), file_name, fixture_name)
+ if verbosity >= 3:
+ self.stdout.write("Trying %s for %s fixture '%s'...\n" % \
+ (humanize(fixture_dir), file_name, fixture_name))
full_path = os.path.join(fixture_dir, file_name)
open_method = compression_types[compression_format]
try:
fixture = open_method(full_path, 'r')
if label_found:
fixture.close()
- print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
- (fixture_name, humanize(fixture_dir)))
+ self.stderr.write(self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting.\n" %
+ (fixture_name, humanize(fixture_dir))))
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
return
else:
fixture_count += 1
objects_in_fixture = 0
- if verbosity > 0:
- print "Installing %s fixture '%s' from %s." % \
- (format, fixture_name, humanize(fixture_dir))
+ loaded_objects_in_fixture = 0
+ if verbosity >= 2:
+ self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
+ (format, fixture_name, humanize(fixture_dir)))
try:
objects = serializers.deserialize(format, fixture, using=using)
for obj in objects:
+ objects_in_fixture += 1
if router.allow_syncdb(using, obj.object.__class__):
- objects_in_fixture += 1
+ loaded_objects_in_fixture += 1
models.add(obj.object.__class__)
obj.save(using=using)
- object_count += objects_in_fixture
+ loaded_object_count += loaded_objects_in_fixture
+ fixture_object_count += objects_in_fixture
label_found = True
except (SystemExit, KeyboardInterrupt):
raise
@@ -179,7 +183,7 @@ class Command(BaseCommand):
if show_traceback:
traceback.print_exc()
else:
- sys.stderr.write(
+ self.stderr.write(
self.style.ERROR("Problem installing fixture '%s': %s\n" %
(full_path, ''.join(traceback.format_exception(sys.exc_type,
sys.exc_value, sys.exc_traceback)))))
@@ -189,25 +193,25 @@ class Command(BaseCommand):
# If the fixture we loaded contains 0 objects, assume that an
# error was encountered during fixture loading.
if objects_in_fixture == 0:
- sys.stderr.write(
- self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" %
+ self.stderr.write(
+ self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)\n" %
(fixture_name)))
transaction.rollback(using=using)
transaction.leave_transaction_management(using=using)
return
except Exception, e:
- if verbosity > 1:
- print "No %s fixture '%s' in %s." % \
- (format, fixture_name, humanize(fixture_dir))
+ if verbosity >= 2:
+ self.stdout.write("No %s fixture '%s' in %s.\n" % \
+ (format, fixture_name, humanize(fixture_dir)))
# If we found even one object in a fixture, we need to reset the
# database sequences.
- if object_count > 0:
+ if loaded_object_count > 0:
sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
if sequence_sql:
- if verbosity > 1:
- print "Resetting sequences"
+ if verbosity >= 2:
+ self.stdout.write("Resetting sequences\n")
for line in sequence_sql:
cursor.execute(line)
@@ -215,12 +219,17 @@ class Command(BaseCommand):
transaction.commit(using=using)
transaction.leave_transaction_management(using=using)
- if object_count == 0:
- if verbosity > 0:
- print "No fixtures found."
+ if fixture_object_count == 0:
+ if verbosity >= 1:
+ self.stdout.write("No fixtures found.\n")
else:
- if verbosity > 0:
- print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)
+ if verbosity >= 1:
+ if fixture_object_count == loaded_object_count:
+ self.stdout.write("Installed %d object(s) from %d fixture(s)\n" % (
+ loaded_object_count, fixture_count))
+ else:
+ self.stdout.write("Installed %d object(s) (of %d) from %d fixture(s)\n" % (
+ loaded_object_count, fixture_object_count, fixture_count))
# Close the DB connection. This is required as a workaround for an
# edge case in MySQL: if the same connection is used to
diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
index 6f1a198653..835e06f24a 100644
--- a/django/core/management/commands/syncdb.py
+++ b/django/core/management/commands/syncdb.py
@@ -77,10 +77,12 @@ class Command(NoArgsCommand):
)
# Create the tables for each model
+ if verbosity >= 1:
+ print "Creating tables ..."
for app_name, model_list in manifest.items():
for model in model_list:
# Create the model's database table, if it doesn't already exist.
- if verbosity >= 2:
+ if verbosity >= 3:
print "Processing %s.%s model" % (app_name, model._meta.object_name)
sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
seen_models.add(model)
@@ -108,12 +110,14 @@ class Command(NoArgsCommand):
# Install custom SQL for the app (but only if this
# is a model we've just created)
+ if verbosity >= 1:
+ print "Installing custom SQL ..."
for app_name, model_list in manifest.items():
for model in model_list:
if model in created_models:
custom_sql = custom_sql_for_model(model, self.style, connection)
if custom_sql:
- if verbosity >= 1:
+ if verbosity >= 2:
print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
try:
for sql in custom_sql:
@@ -128,16 +132,18 @@ class Command(NoArgsCommand):
else:
transaction.commit_unless_managed(using=db)
else:
- if verbosity >= 2:
+ if verbosity >= 3:
print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name)
+ if verbosity >= 1:
+ print "Installing indexes ..."
# Install SQL indicies for all newly created models
for app_name, model_list in manifest.items():
for model in model_list:
if model in created_models:
index_sql = connection.creation.sql_indexes_for_model(model, self.style)
if index_sql:
- if verbosity >= 1:
+ if verbosity >= 2:
print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
try:
for sql in index_sql:
diff --git a/django/core/management/commands/testserver.py b/django/core/management/commands/testserver.py
index 6c75a3e2b6..d3d9698c9a 100644
--- a/django/core/management/commands/testserver.py
+++ b/django/core/management/commands/testserver.py
@@ -4,6 +4,8 @@ from optparse import make_option
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
+ make_option('--noinput', action='store_false', dest='interactive', default=True,
+ help='Tells Django to NOT prompt the user for input of any kind.'),
make_option('--addrport', action='store', dest='addrport',
type='string', default='',
help='port number or ipaddr:port to run the server on'),
@@ -18,10 +20,11 @@ class Command(BaseCommand):
from django.db import connection
verbosity = int(options.get('verbosity', 1))
+ interactive = options.get('interactive', True)
addrport = options.get('addrport')
# Create a test database.
- db_name = connection.creation.create_test_db(verbosity=verbosity)
+ db_name = connection.creation.create_test_db(verbosity=verbosity, autoclobber=not interactive)
# Import the fixture data into the test database.
call_command('loaddata', *fixture_labels, **{'verbosity': verbosity})
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index cad57a5d9f..5e565f75d6 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -30,6 +30,40 @@ _prefixes = {}
# Overridden URLconfs for each thread are stored here.
_urlconfs = {}
+class ResolverMatch(object):
+ def __init__(self, func, args, kwargs, url_name=None, app_name=None, namespaces=None):
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+ self.app_name = app_name
+ if namespaces:
+ self.namespaces = [x for x in namespaces if x]
+ else:
+ self.namespaces = []
+ if not url_name:
+ if not hasattr(func, '__name__'):
+ # An instance of a callable class
+ url_name = '.'.join([func.__class__.__module__, func.__class__.__name__])
+ else:
+ # A function
+ url_name = '.'.join([func.__module__, func.__name__])
+ self.url_name = url_name
+
+ def namespace(self):
+ return ':'.join(self.namespaces)
+ namespace = property(namespace)
+
+ def view_name(self):
+ return ':'.join([ x for x in [ self.namespace, self.url_name ] if x ])
+ view_name = property(view_name)
+
+ def __getitem__(self, index):
+ return (self.func, self.args, self.kwargs)[index]
+
+ def __repr__(self):
+ return "ResolverMatch(func=%s, args=%s, kwargs=%s, url_name='%s', app_name='%s', namespace='%s')" % (
+ self.func, self.args, self.kwargs, self.url_name, self.app_name, self.namespace)
+
class Resolver404(Http404):
pass
@@ -120,7 +154,7 @@ class RegexURLPattern(object):
# In both cases, pass any extra_kwargs as **kwargs.
kwargs.update(self.default_args)
- return self.callback, args, kwargs
+ return ResolverMatch(self.callback, args, kwargs, self.name)
def _get_callback(self):
if self._callback is not None:
@@ -183,7 +217,8 @@ class RegexURLResolver(object):
else:
bits = normalize(p_pattern)
lookups.appendlist(pattern.callback, (bits, p_pattern))
- lookups.appendlist(pattern.name, (bits, p_pattern))
+ if pattern.name is not None:
+ lookups.appendlist(pattern.name, (bits, p_pattern))
self._reverse_dict = lookups
self._namespace_dict = namespaces
self._app_dict = apps
@@ -217,17 +252,17 @@ class RegexURLResolver(object):
except Resolver404, e:
sub_tried = e.args[0].get('tried')
if sub_tried is not None:
- tried.extend([(pattern.regex.pattern + ' ' + t) for t in sub_tried])
+ tried.extend([[pattern] + t for t in sub_tried])
else:
- tried.append(pattern.regex.pattern)
+ tried.append([pattern])
else:
if sub_match:
sub_match_dict = dict([(smart_str(k), v) for k, v in match.groupdict().items()])
sub_match_dict.update(self.default_kwargs)
- for k, v in sub_match[2].iteritems():
+ for k, v in sub_match.kwargs.iteritems():
sub_match_dict[smart_str(k)] = v
- return sub_match[0], sub_match[1], sub_match_dict
- tried.append(pattern.regex.pattern)
+ return ResolverMatch(sub_match.func, sub_match.args, sub_match_dict, sub_match.url_name, self.app_name or sub_match.app_name, [self.namespace] + sub_match.namespaces)
+ tried.append([pattern])
raise Resolver404({'tried': tried, 'path': new_path})
raise Resolver404({'path' : path})
@@ -249,7 +284,12 @@ class RegexURLResolver(object):
url_patterns = property(_get_url_patterns)
def _resolve_special(self, view_type):
- callback = getattr(self.urlconf_module, 'handler%s' % view_type)
+ callback = getattr(self.urlconf_module, 'handler%s' % view_type, None)
+ if not callback:
+ # No handler specified in file; use default
+ # Lazy import, since urls.defaults imports this file
+ from django.conf.urls import defaults
+ callback = getattr(defaults, 'handler%s' % view_type)
try:
return get_callable(callback), {}
except (ImportError, AttributeError), e: