diff options
| author | Adrian Holovaty <adrian@holovaty.com> | 2007-09-15 22:00:35 +0000 |
|---|---|---|
| committer | Adrian Holovaty <adrian@holovaty.com> | 2007-09-15 22:00:35 +0000 |
| commit | 28a4aa6f49b11881d43a585f118a3d0537ba9084 (patch) | |
| tree | b4c3cebac7c02b5e8e2aab4729eb18800d3bcf1c /django | |
| parent | ca33d307dee3cf68cc9cd2ccfae00c7ff23ea890 (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.py | 14 | ||||
| -rw-r--r-- | django/contrib/auth/handlers/modpython.py | 4 | ||||
| -rw-r--r-- | django/contrib/auth/models.py | 53 | ||||
| -rw-r--r-- | django/contrib/sessions/backends/__init__.py | 0 | ||||
| -rw-r--r-- | django/contrib/sessions/backends/base.py | 143 | ||||
| -rw-r--r-- | django/contrib/sessions/backends/cache.py | 26 | ||||
| -rw-r--r-- | django/contrib/sessions/backends/db.py | 49 | ||||
| -rw-r--r-- | django/contrib/sessions/backends/file.py | 67 | ||||
| -rw-r--r-- | django/contrib/sessions/middleware.py | 89 | ||||
| -rw-r--r-- | django/contrib/sessions/models.py | 3 | ||||
| -rw-r--r-- | django/contrib/sessions/tests.py | 60 | ||||
| -rw-r--r-- | django/db/__init__.py | 53 | ||||
| -rw-r--r-- | django/test/client.py | 23 | ||||
| -rw-r--r-- | django/views/i18n.py | 2 |
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: |
