summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2007-09-15 22:00:35 +0000
committerAdrian Holovaty <adrian@holovaty.com>2007-09-15 22:00:35 +0000
commit28a4aa6f49b11881d43a585f118a3d0537ba9084 (patch)
treeb4c3cebac7c02b5e8e2aab4729eb18800d3bcf1c /django
parentca33d307dee3cf68cc9cd2ccfae00c7ff23ea890 (diff)
queryset-refactor: Merged to [6340]
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6341 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/conf/global_settings.py14
-rw-r--r--django/contrib/auth/handlers/modpython.py4
-rw-r--r--django/contrib/auth/models.py53
-rw-r--r--django/contrib/sessions/backends/__init__.py0
-rw-r--r--django/contrib/sessions/backends/base.py143
-rw-r--r--django/contrib/sessions/backends/cache.py26
-rw-r--r--django/contrib/sessions/backends/db.py49
-rw-r--r--django/contrib/sessions/backends/file.py67
-rw-r--r--django/contrib/sessions/middleware.py89
-rw-r--r--django/contrib/sessions/models.py3
-rw-r--r--django/contrib/sessions/tests.py60
-rw-r--r--django/db/__init__.py53
-rw-r--r--django/test/client.py23
-rw-r--r--django/views/i18n.py2
14 files changed, 434 insertions, 152 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index c8420f3307..b3cbf095c3 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -271,12 +271,14 @@ MIDDLEWARE_CLASSES = (
# SESSIONS #
############
-SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
-SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
-SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
-SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
-SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
-SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
+SESSION_COOKIE_NAME = 'sessionid' # Cookie name. This can be whatever you want.
+SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2 # Age of cookie, in seconds (default: 2 weeks).
+SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or None for standard domain cookie.
+SESSION_COOKIE_SECURE = False # Whether the session cookie should be secure (https:// only).
+SESSION_SAVE_EVERY_REQUEST = False # Whether to save the session data on every request.
+SESSION_EXPIRE_AT_BROWSER_CLOSE = False # Whether sessions expire when a user closes his browser.
+SESSION_ENGINE = 'django.contrib.sessions.backends.db' # The module to store session data
+SESSION_FILE_PATH = '/tmp/' # Directory to store session files if using the file session module
#########
# CACHE #
diff --git a/django/contrib/auth/handlers/modpython.py b/django/contrib/auth/handlers/modpython.py
index c7d921313d..de961fa4dd 100644
--- a/django/contrib/auth/handlers/modpython.py
+++ b/django/contrib/auth/handlers/modpython.py
@@ -10,6 +10,10 @@ def authenhandler(req, **kwargs):
# that so that the following import works
os.environ.update(req.subprocess_env)
+ # apache 2.2 requires a call to req.get_basic_auth_pw() before
+ # req.user and friends are available.
+ req.get_basic_auth_pw()
+
# check for PythonOptions
_str_to_bool = lambda s: s.lower() in ('1', 'true', 'on', 'yes')
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index 7cbeb26af6..2f9954e742 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -15,25 +15,43 @@ try:
except NameError:
from sets import Set as set # Python 2.3 fallback
+def get_hexdigest(algorithm, salt, raw_password):
+ """
+ Returns a string of the hexdigest of the given plaintext password and salt
+ using the given algorithm ('md5', 'sha1' or 'crypt').
+ """
+ raw_password, salt = smart_str(raw_password), smart_str(salt)
+ if algorithm == 'crypt':
+ try:
+ import crypt
+ except ImportError:
+ raise ValueError('"crypt" password algorithm not supported in this environment')
+ return crypt.crypt(raw_password, salt)
+ # The rest of the supported algorithms are supported by hashlib, but
+ # hashlib is only available in Python 2.5.
+ try:
+ import hashlib
+ except ImportError:
+ if algorithm == 'md5':
+ import md5
+ return md5.new(salt + raw_password).hexdigest()
+ elif algorithm == 'sha1':
+ import sha
+ return sha.new(salt + raw_password).hexdigest()
+ else:
+ if algorithm == 'md5':
+ return hashlib.md5(salt + raw_password).hexdigest()
+ elif algorithm == 'sha1':
+ return hashlib.sha1(salt + raw_password).hexdigest()
+ raise ValueError("Got unknown password algorithm type in password.")
+
def check_password(raw_password, enc_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes.
"""
algo, salt, hsh = enc_password.split('$')
- if algo == 'md5':
- import md5
- return hsh == md5.new(smart_str(salt + raw_password)).hexdigest()
- elif algo == 'sha1':
- import sha
- return hsh == sha.new(smart_str(salt + raw_password)).hexdigest()
- elif algo == 'crypt':
- try:
- import crypt
- except ImportError:
- raise ValueError, "Crypt password algorithm not supported in this environment."
- return hsh == crypt.crypt(smart_str(raw_password), smart_str(salt))
- raise ValueError, "Got unknown password algorithm type in password."
+ return hsh == get_hexdigest(algo, salt, raw_password)
class SiteProfileNotAvailable(Exception):
pass
@@ -162,10 +180,10 @@ class User(models.Model):
return full_name.strip()
def set_password(self, raw_password):
- import sha, random
+ import random
algo = 'sha1'
- salt = sha.new(str(random.random())).hexdigest()[:5]
- hsh = sha.new(salt + smart_str(raw_password)).hexdigest()
+ salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
+ hsh = get_hexdigest(algo, salt, raw_password)
self.password = '%s$%s$%s' % (algo, salt, hsh)
def check_password(self, raw_password):
@@ -176,8 +194,7 @@ class User(models.Model):
# Backwards-compatibility check. Older passwords won't include the
# algorithm or salt.
if '$' not in self.password:
- import md5
- is_correct = (self.password == md5.new(smart_str(raw_password)).hexdigest())
+ is_correct = (self.password == get_hexdigest('md5', '', raw_password))
if is_correct:
# Convert the password to the new, more secure format.
self.set_password(raw_password)
diff --git a/django/contrib/sessions/backends/__init__.py b/django/contrib/sessions/backends/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/django/contrib/sessions/backends/__init__.py
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
new file mode 100644
index 0000000000..9471706363
--- /dev/null
+++ b/django/contrib/sessions/backends/base.py
@@ -0,0 +1,143 @@
+import base64
+import md5
+import os
+import random
+import sys
+import time
+from django.conf import settings
+from django.core.exceptions import SuspiciousOperation
+
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+class SessionBase(object):
+ """
+ Base class for all Session classes.
+ """
+
+ TEST_COOKIE_NAME = 'testcookie'
+ TEST_COOKIE_VALUE = 'worked'
+
+ def __init__(self, session_key=None):
+ self._session_key = session_key
+ self.accessed = False
+ self.modified = False
+
+ def __contains__(self, key):
+ return key in self._session
+
+ def __getitem__(self, key):
+ return self._session[key]
+
+ def __setitem__(self, key, value):
+ self._session[key] = value
+ self.modified = True
+
+ def __delitem__(self, key):
+ del self._session[key]
+ self.modified = True
+
+ def keys(self):
+ return self._session.keys()
+
+ def items(self):
+ return self._session.items()
+
+ def get(self, key, default=None):
+ return self._session.get(key, default)
+
+ def pop(self, key, *args):
+ return self._session.pop(key, *args)
+
+ def set_test_cookie(self):
+ self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE
+
+ def test_cookie_worked(self):
+ return self.get(self.TEST_COOKIE_NAME) == self.TEST_COOKIE_VALUE
+
+ def delete_test_cookie(self):
+ del self[self.TEST_COOKIE_NAME]
+
+ def encode(self, session_dict):
+ "Returns the given session dictionary pickled and encoded as a string."
+ pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
+ pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+ return base64.encodestring(pickled + pickled_md5)
+
+ def decode(self, session_data):
+ encoded_data = base64.decodestring(session_data)
+ pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
+ if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ raise SuspiciousOperation("User tampered with session cookie.")
+ try:
+ return pickle.loads(pickled)
+ # Unpickling can cause a variety of exceptions. If something happens,
+ # just return an empty dictionary (an empty session).
+ except:
+ return {}
+
+ def _get_new_session_key(self):
+ "Returns session key that isn't being used."
+ # The random module is seeded when this Apache child is created.
+ # Use settings.SECRET_KEY as added salt.
+ while 1:
+ session_key = md5.new("%s%s%s%s" % (random.randint(0, sys.maxint - 1),
+ os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest()
+ if not self.exists(session_key):
+ break
+ return session_key
+
+ def _get_session_key(self):
+ if self._session_key:
+ return self._session_key
+ else:
+ self._session_key = self._get_new_session_key()
+ return self._session_key
+
+ def _set_session_key(self, session_key):
+ self._session_key = session_key
+
+ session_key = property(_get_session_key, _set_session_key)
+
+ def _get_session(self):
+ # Lazily loads session from storage.
+ self.accessed = True
+ try:
+ return self._session_cache
+ except AttributeError:
+ if self.session_key is None:
+ self._session_cache = {}
+ else:
+ self._session_cache = self.load()
+ return self._session_cache
+
+ _session = property(_get_session)
+
+ # Methods that child classes must implement.
+
+ def exists(self, session_key):
+ """
+ Returns True if the given session_key already exists.
+ """
+ raise NotImplementedError
+
+ def save(self):
+ """
+ Saves the session data.
+ """
+ raise NotImplementedError
+
+ def delete(self, session_key):
+ """
+ Clears out the session data under this key.
+ """
+ raise NotImplementedError
+
+ def load(self):
+ """
+ Loads the session data and returns a dictionary.
+ """
+ raise NotImplementedError
+
diff --git a/django/contrib/sessions/backends/cache.py b/django/contrib/sessions/backends/cache.py
new file mode 100644
index 0000000000..c3e641e691
--- /dev/null
+++ b/django/contrib/sessions/backends/cache.py
@@ -0,0 +1,26 @@
+from django.conf import settings
+from django.contrib.sessions.backends.base import SessionBase
+from django.core.cache import cache
+
+class SessionStore(SessionBase):
+ """
+ A cache-based session store.
+ """
+ def __init__(self, session_key=None):
+ self._cache = cache
+ super(SessionStore, self).__init__(session_key)
+
+ def load(self):
+ session_data = self._cache.get(self.session_key)
+ return session_data or {}
+
+ def save(self):
+ self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE)
+
+ def exists(self, session_key):
+ if self._cache.get(session_key):
+ return True
+ return False
+
+ def delete(self, session_key):
+ self._cache.delete(session_key) \ No newline at end of file
diff --git a/django/contrib/sessions/backends/db.py b/django/contrib/sessions/backends/db.py
new file mode 100644
index 0000000000..d1496d63bf
--- /dev/null
+++ b/django/contrib/sessions/backends/db.py
@@ -0,0 +1,49 @@
+from django.conf import settings
+from django.contrib.sessions.models import Session
+from django.contrib.sessions.backends.base import SessionBase
+from django.core.exceptions import SuspiciousOperation
+import datetime
+
+class SessionStore(SessionBase):
+ """
+ Implements database session store
+ """
+ def __init__(self, session_key=None):
+ super(SessionStore, self).__init__(session_key)
+
+ def load(self):
+ try:
+ s = Session.objects.get(
+ session_key = self.session_key,
+ expire_date__gt=datetime.datetime.now()
+ )
+ return self.decode(s.session_data)
+ except (Session.DoesNotExist, SuspiciousOperation):
+
+ # Create a new session_key for extra security.
+ self.session_key = self._get_new_session_key()
+ self._session_cache = {}
+
+ # Save immediately to minimize collision
+ self.save()
+ return {}
+
+ def exists(self, session_key):
+ try:
+ Session.objects.get(session_key=session_key)
+ except Session.DoesNotExist:
+ return False
+ return True
+
+ def save(self):
+ Session.objects.create(
+ session_key = self.session_key,
+ session_data = self.encode(self._session),
+ expire_date = datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)
+ )
+
+ def delete(self, session_key):
+ try:
+ Session.objects.get(session_key=session_key).delete()
+ except Session.DoesNotExist:
+ pass \ No newline at end of file
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
new file mode 100644
index 0000000000..062acca323
--- /dev/null
+++ b/django/contrib/sessions/backends/file.py
@@ -0,0 +1,67 @@
+import os
+from django.conf import settings
+from django.contrib.sessions.backends.base import SessionBase
+from django.core.exceptions import SuspiciousOperation
+
+class SessionStore(SessionBase):
+ """
+ Implements a file based session store.
+ """
+ def __init__(self, session_key=None):
+ self.storage_path = settings.SESSION_FILE_PATH
+ self.file_prefix = settings.SESSION_COOKIE_NAME
+ super(SessionStore, self).__init__(session_key)
+
+ def _key_to_file(self, session_key=None):
+ """
+ Get the file associated with this session key.
+ """
+ if session_key is None:
+ session_key = self.session_key
+
+ # Make sure we're not vulnerable to directory traversal. Session keys
+ # should always be md5s, so they should never contain directory components.
+ if os.path.sep in session_key:
+ raise SuspiciousOperation("Invalid characters (directory components) in session key")
+
+ return os.path.join(self.storage_path, self.file_prefix + session_key)
+
+ def load(self):
+ session_data = {}
+ try:
+ session_file = open(self._key_to_file(), "rb")
+ try:
+ session_data = self.decode(session_file.read())
+ except(EOFError, SuspiciousOperation):
+ self._session_key = self._get_new_session_key()
+ self._session_cache = {}
+ self.save()
+ finally:
+ session_file.close()
+ except(IOError):
+ pass
+ return session_data
+
+ def save(self):
+ try:
+ f = open(self._key_to_file(self.session_key), "wb")
+ try:
+ f.write(self.encode(self._session))
+ finally:
+ f.close()
+ except(IOError, EOFError):
+ pass
+
+ def exists(self, session_key):
+ if os.path.exists(self._key_to_file(session_key)):
+ return True
+ return False
+
+ def delete(self, session_key):
+ try:
+ os.unlink(self._key_to_file(session_key))
+ except OSError:
+ pass
+
+ def clean(self):
+ pass \ No newline at end of file
diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py
index 2531c8e244..4c3c5acc43 100644
--- a/django/contrib/sessions/middleware.py
+++ b/django/contrib/sessions/middleware.py
@@ -1,6 +1,4 @@
from django.conf import settings
-from django.contrib.sessions.models import Session
-from django.core.exceptions import SuspiciousOperation
from django.utils.cache import patch_vary_headers
from email.Utils import formatdate
import datetime
@@ -9,73 +7,11 @@ import time
TEST_COOKIE_NAME = 'testcookie'
TEST_COOKIE_VALUE = 'worked'
-class SessionWrapper(object):
- def __init__(self, session_key):
- self.session_key = session_key
- self.accessed = False
- self.modified = False
-
- def __contains__(self, key):
- return key in self._session
-
- def __getitem__(self, key):
- return self._session[key]
-
- def __setitem__(self, key, value):
- self._session[key] = value
- self.modified = True
-
- def __delitem__(self, key):
- del self._session[key]
- self.modified = True
-
- def keys(self):
- return self._session.keys()
-
- def items(self):
- return self._session.items()
-
- def get(self, key, default=None):
- return self._session.get(key, default)
-
- def pop(self, key, *args):
- self.modified = self.modified or key in self._session
- return self._session.pop(key, *args)
-
- def set_test_cookie(self):
- self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE
-
- def test_cookie_worked(self):
- return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE
-
- def delete_test_cookie(self):
- del self[TEST_COOKIE_NAME]
-
- def _get_session(self):
- # Lazily loads session from storage.
- self.accessed = True
- try:
- return self._session_cache
- except AttributeError:
- if self.session_key is None:
- self._session_cache = {}
- else:
- try:
- s = Session.objects.get(session_key=self.session_key,
- expire_date__gt=datetime.datetime.now())
- self._session_cache = s.get_decoded()
- except (Session.DoesNotExist, SuspiciousOperation):
- self._session_cache = {}
- # Set the session_key to None to force creation of a new
- # key, for extra security.
- self.session_key = None
- return self._session_cache
-
- _session = property(_get_session)
-
class SessionMiddleware(object):
+
def process_request(self, request):
- request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
+ engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
+ request.session = engine.SessionStore(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None))
def process_response(self, request, response):
# If request.session was modified, or if response.session was set, save
@@ -89,25 +25,22 @@ class SessionMiddleware(object):
if accessed:
patch_vary_headers(response, ('Cookie',))
if modified or settings.SESSION_SAVE_EVERY_REQUEST:
- if request.session.session_key:
- session_key = request.session.session_key
- else:
- obj = Session.objects.get_new_session_object()
- session_key = obj.session_key
-
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
max_age = None
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 = (rfcdate[:7] + "-" + rfcdate[8:11]
- + "-" + rfcdate[12:26] + "GMT")
- new_session = Session.objects.save(session_key, request.session._session,
- datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
- response.set_cookie(settings.SESSION_COOKIE_NAME, session_key,
+ expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
+ datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
+
+ # Save the seesion data and refresh the client cookie.
+ request.session.save()
+ response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key,
max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
secure=settings.SESSION_COOKIE_SECURE or None)
+
return response
diff --git a/django/contrib/sessions/models.py b/django/contrib/sessions/models.py
index fda10c9743..c086396947 100644
--- a/django/contrib/sessions/models.py
+++ b/django/contrib/sessions/models.py
@@ -1,4 +1,4 @@
-import base64, md5, random, sys, datetime, os, time
+import base64, md5, random, sys, datetime
import cPickle as pickle
from django.db import models
from django.utils.translation import ugettext_lazy as _
@@ -74,6 +74,7 @@ class Session(models.Model):
session_data = models.TextField(_('session data'))
expire_date = models.DateTimeField(_('expire date'))
objects = SessionManager()
+
class Meta:
db_table = 'django_session'
verbose_name = _('session')
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index e83442123e..cfb475fc49 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -1,35 +1,59 @@
r"""
->>> s = SessionWrapper(None)
-Inject data into the session cache.
->>> s._session_cache = {}
->>> s._session_cache['some key'] = 'exists'
+>>> from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
+>>> from django.contrib.sessions.backends.cache import SessionStore as CacheSession
+>>> from django.contrib.sessions.backends.file import SessionStore as FileSession
->>> s.accessed
+>>> db_session = DatabaseSession()
+>>> db_session.modified
False
->>> s.modified
-False
-
->>> s.pop('non existant key', 'does not exist')
+>>> db_session['cat'] = "dog"
+>>> db_session.modified
+True
+>>> db_session.pop('cat')
+'dog'
+>>> db_session.pop('some key', 'does not exist')
'does not exist'
->>> s.accessed
+>>> db_session.save()
+>>> db_session.exists(db_session.session_key)
True
->>> s.modified
+>>> db_session.delete(db_session.session_key)
+>>> db_session.exists(db_session.session_key)
False
->>> s.pop('some key')
-'exists'
->>> s.accessed
+>>> file_session = FileSession()
+>>> file_session.modified
+False
+>>> file_session['cat'] = "dog"
+>>> file_session.modified
True
->>> s.modified
+>>> file_session.pop('cat')
+'dog'
+>>> file_session.pop('some key', 'does not exist')
+'does not exist'
+>>> file_session.save()
+>>> file_session.exists(file_session.session_key)
True
+>>> file_session.delete(file_session.session_key)
+>>> file_session.exists(file_session.session_key)
+False
->>> s.pop('some key', 'does not exist')
+>>> cache_session = CacheSession()
+>>> cache_session.modified
+False
+>>> cache_session['cat'] = "dog"
+>>> cache_session.modified
+True
+>>> cache_session.pop('cat')
+'dog'
+>>> cache_session.pop('some key', 'does not exist')
'does not exist'
+>>> cache_session.save()
+>>> cache_session.delete(cache_session.session_key)
+>>> cache_session.exists(cache_session.session_key)
+False
"""
-from django.contrib.sessions.middleware import SessionWrapper
-
if __name__ == '__main__':
import doctest
doctest.testmod()
diff --git a/django/db/__init__.py b/django/db/__init__.py
index 33223d200a..d4ea1403bd 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -1,6 +1,9 @@
+import os
from django.conf import settings
from django.core import signals
+from django.core.exceptions import ImproperlyConfigured
from django.dispatch import dispatcher
+from django.utils.functional import curry
__all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError')
@@ -8,25 +11,43 @@ if not settings.DATABASE_ENGINE:
settings.DATABASE_ENGINE = 'dummy'
try:
- backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
+ # Most of the time, the database backend will be one of the official
+ # backends that ships with Django, so look there first.
+ _import_path = 'django.db.backends.'
+ backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
except ImportError, e:
- # The database backend wasn't found. Display a helpful error message
- # listing all possible database backends.
- from django.core.exceptions import ImproperlyConfigured
- import os
- backend_dir = os.path.join(__path__[0], 'backends')
- available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
- available_backends.sort()
- if settings.DATABASE_ENGINE not in available_backends:
- raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s" % \
- (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
- else:
- raise # If there's some other error, this must be an error in Django itself.
+ # If the import failed, we might be looking for a database backend
+ # distributed external to Django. So we'll try that next.
+ try:
+ _import_path = ''
+ backend = __import__('%s.base' % settings.DATABASE_ENGINE, {}, {}, [''])
+ except ImportError, e_user:
+ # The database backend wasn't found. Display a helpful error message
+ # listing all possible (built-in) database backends.
+ backend_dir = os.path.join(__path__[0], 'backends')
+ available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')]
+ available_backends.sort()
+ if settings.DATABASE_ENGINE not in available_backends:
+ raise ImproperlyConfigured, "%r isn't an available database backend. Available options are: %s" % \
+ (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends)))
+ else:
+ raise # If there's some other error, this must be an error in Django itself.
-get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, {}, {}, [''])
-get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, {}, {}, [''])
-runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, {}, {}, ['']).runshell()
+def _import_database_module(import_path='', module_name=''):
+ """Lazyily import a database module when requested."""
+ return __import__('%s%s.%s' % (_import_path, settings.DATABASE_ENGINE, module_name), {}, {}, [''])
+# We don't want to import the introspect/creation modules unless
+# someone asks for 'em, so lazily load them on demmand.
+get_introspection_module = curry(_import_database_module, _import_path, 'introspection')
+get_creation_module = curry(_import_database_module, _import_path, 'creation')
+
+# We want runshell() to work the same way, but we have to treat it a
+# little differently (since it just runs instead of returning a module like
+# the above) and wrap the lazily-loaded runshell() method.
+runshell = lambda: _import_database_module(_import_path, "client").runshell()
+
+# Convenient aliases for backend bits.
connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
DatabaseError = backend.DatabaseError
IntegrityError = backend.IntegrityError
diff --git a/django/test/client.py b/django/test/client.py
index faacc5bf9e..6a05d9dd9c 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -4,8 +4,6 @@ from cStringIO import StringIO
from urlparse import urlparse
from django.conf import settings
from django.contrib.auth import authenticate, login
-from django.contrib.sessions.models import Session
-from django.contrib.sessions.middleware import SessionWrapper
from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIRequest
from django.core.signals import got_request_exception
@@ -132,9 +130,10 @@ class Client:
def _session(self):
"Obtain the current session variables"
if 'django.contrib.sessions' in settings.INSTALLED_APPS:
+ engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
if cookie:
- return SessionWrapper(cookie.value)
+ return engine.SessionStore(cookie.value)
return {}
session = property(_session)
@@ -247,24 +246,23 @@ class Client:
"""
user = authenticate(**credentials)
if user and user.is_active and 'django.contrib.sessions' in settings.INSTALLED_APPS:
- obj = Session.objects.get_new_session_object()
+ engine = __import__(settings.SESSION_ENGINE, {}, {}, [''])
# Create a fake request to store login details
request = HttpRequest()
- request.session = SessionWrapper(obj.session_key)
+ request.session = engine.SessionStore()
login(request, user)
# Set the cookie to represent the session
- self.cookies[settings.SESSION_COOKIE_NAME] = obj.session_key
+ self.cookies[settings.SESSION_COOKIE_NAME] = request.session.session_key
self.cookies[settings.SESSION_COOKIE_NAME]['max-age'] = None
self.cookies[settings.SESSION_COOKIE_NAME]['path'] = '/'
self.cookies[settings.SESSION_COOKIE_NAME]['domain'] = settings.SESSION_COOKIE_DOMAIN
self.cookies[settings.SESSION_COOKIE_NAME]['secure'] = settings.SESSION_COOKIE_SECURE or None
self.cookies[settings.SESSION_COOKIE_NAME]['expires'] = None
- # Set the session values
- Session.objects.save(obj.session_key, request.session._session,
- datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
+ # Save the session values
+ request.session.save()
return True
else:
@@ -275,9 +273,6 @@ class Client:
Causes the authenticated user to be logged out.
"""
- try:
- Session.objects.get(session_key=self.cookies['sessionid'].value).delete()
- except KeyError:
- pass
-
+ session = __import__(settings.SESSION_ENGINE, {}, {}, ['']).SessionStore()
+ session.delete(session_key=self.cookies['sessionid'].value)
self.cookies = SimpleCookie()
diff --git a/django/views/i18n.py b/django/views/i18n.py
index 5b50f75d23..cccec13941 100644
--- a/django/views/i18n.py
+++ b/django/views/i18n.py
@@ -16,7 +16,7 @@ def set_language(request):
redirect to the page in the request (the 'next' parameter) without changing
any state.
"""
- next = request.GET.get('next', None)
+ next = request.REQUEST.get('next', None)
if not next:
next = request.META.get('HTTP_REFERER', None)
if not next: