mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Merged to [6340]
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6341 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
ca33d307de
commit
28a4aa6f49
1
AUTHORS
1
AUTHORS
@ -87,6 +87,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Matt Croydon <http://www.postneo.com/>
|
||||
flavio.curella@gmail.com
|
||||
Jure Cuhalev <gandalf@owca.info>
|
||||
John D'Agostino <john.dagostino@gmail.com>
|
||||
dackze+django@gmail.com
|
||||
David Danier <goliath.mailinglist@gmx.de>
|
||||
Dirk Datzert <dummy@habmalnefrage.de>
|
||||
|
@ -277,6 +277,8 @@ SESSION_COOKIE_DOMAIN = None # A string like ".lawrence.com", or No
|
||||
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 #
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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)
|
||||
|
0
django/contrib/sessions/backends/__init__.py
Normal file
0
django/contrib/sessions/backends/__init__.py
Normal file
143
django/contrib/sessions/backends/base.py
Normal file
143
django/contrib/sessions/backends/base.py
Normal file
@ -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
|
||||
|
26
django/contrib/sessions/backends/cache.py
Normal file
26
django/contrib/sessions/backends/cache.py
Normal file
@ -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)
|
49
django/contrib/sessions/backends/db.py
Normal file
49
django/contrib/sessions/backends/db.py
Normal file
@ -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
|
67
django/contrib/sessions/backends/file.py
Normal file
67
django/contrib/sessions/backends/file.py
Normal file
@ -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
|
@ -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
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
True
|
||||
|
||||
>>> s.pop('some key', 'does not exist')
|
||||
>>> 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
|
||||
|
||||
>>> 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()
|
||||
|
@ -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,12 +11,19 @@ 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:
|
||||
# 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 database backends.
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
import os
|
||||
# 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()
|
||||
@ -23,10 +33,21 @@ except ImportError, e:
|
||||
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
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -21,7 +21,7 @@ file, you'll need to use mod_python's ``PythonAuthenHandler`` directive along
|
||||
with the standard ``Auth*`` and ``Require`` directives::
|
||||
|
||||
<Location /example/>
|
||||
AuthType basic
|
||||
AuthType Basic
|
||||
AuthName "example.com"
|
||||
Require valid-user
|
||||
|
||||
@ -29,6 +29,49 @@ with the standard ``Auth*`` and ``Require`` directives::
|
||||
PythonAuthenHandler django.contrib.auth.handlers.modpython
|
||||
</Location>
|
||||
|
||||
.. admonition:: Using the authentication handler with Apache 2.2
|
||||
|
||||
If you're using Apache 2.2, you'll need to take a couple extra steps.
|
||||
|
||||
You'll need to ensure that ``mod_auth_basic`` and ``mod_authz_user``
|
||||
are loaded. These might be compiled staticly into Apache, or you might
|
||||
need to use ``LoadModule`` to load them dynamically (as shown in the
|
||||
example at the bottom of this note).
|
||||
|
||||
You'll also need to insert configuration directives that prevent Apache
|
||||
from trying to use other authentication modules. Depnding on which other
|
||||
authentication modules you have loaded, you might need one or more of
|
||||
the following directives::
|
||||
|
||||
AuthBasicAuthoritative Off
|
||||
AuthDefaultAuthoritative Off
|
||||
AuthzLDAPAuthoritative Off
|
||||
AuthzDBMAuthoritative Off
|
||||
AuthzDefaultAuthoritative Off
|
||||
AuthzGroupFileAuthoritative Off
|
||||
AuthzOwnerAuthoritative Off
|
||||
AuthzUserAuthoritative Off
|
||||
|
||||
A complete configuration, with differences between Apache 2.0 and
|
||||
Apache 2.2 marked in bold, would look something like:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
**LoadModule auth_basic_module modules/mod_auth_basic.so**
|
||||
**LoadModule authz_user_module modules/mod_authz_user.so**
|
||||
|
||||
...
|
||||
|
||||
<Location /exmaple/>
|
||||
AuthType Basic
|
||||
AuthName "example.com"
|
||||
**AuthBasicAuthoritative Off**
|
||||
Require valid-user
|
||||
|
||||
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
|
||||
PythonAuthenHandler django.contrib.auth.handlers.modpython
|
||||
</Location>
|
||||
|
||||
By default, the authentication handler will limit access to the ``/example/``
|
||||
location to users marked as staff members. You can use a set of
|
||||
``PythonOption`` directives to modify this behavior:
|
||||
|
@ -524,6 +524,15 @@ the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom
|
||||
``max_age`` in a ``cache_control`` decorator, the decorator will take
|
||||
precedence, and the header values will be merged correctly.)
|
||||
|
||||
If you want to use headers to disable caching altogether,
|
||||
``django.views.decorators.never_cache`` is a view decorator that adds
|
||||
headers to ensure the response won't be cached by browsers or other caches. Example::
|
||||
|
||||
from django.views.decorators.cache import never_cache
|
||||
@never_cache
|
||||
def myview(request):
|
||||
...
|
||||
|
||||
.. _`Cache-Control spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
|
||||
Other optimizations
|
||||
|
258
docs/contenttypes.txt
Normal file
258
docs/contenttypes.txt
Normal file
@ -0,0 +1,258 @@
|
||||
==========================
|
||||
The contenttypes framework
|
||||
==========================
|
||||
|
||||
Django includes a "contenttypes" application that can track all of
|
||||
the models installed in your Django-powered project, providing a
|
||||
high-level, generic interface for working with your models.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
At the heart of the contenttypes application is the ``ContentType``
|
||||
model, which lives at
|
||||
``django.contrib.contenttypes.models.ContentType``. Instances of
|
||||
``ContentType`` represent and store information about the models
|
||||
installed in your project, and new instances of ``ContentType`` are
|
||||
automatically created whenever new models are installed.
|
||||
|
||||
Instances of ``ContentType`` have methods for returning the model
|
||||
classes they represent and for querying objects from those models.
|
||||
``ContentType`` also has a `custom manager`_ that adds methods for
|
||||
working with ``ContentType`` and for obtaining instances of
|
||||
``ContentType`` for a particular model.
|
||||
|
||||
Relations between your models and ``ContentType`` can also be used to
|
||||
enable "generic" relationships between an instance of one of your
|
||||
models and instances of any model you have installed.
|
||||
|
||||
.. _custom manager: ../model-api/#custom-managers
|
||||
|
||||
Installing the contenttypes framework
|
||||
=====================================
|
||||
|
||||
The contenttypes framework is included in the default
|
||||
``INSTALLED_APPS`` list created by ``django-admin.py startproject``,
|
||||
but if you've removed it or if you manually set up your
|
||||
``INSTALLED_APPS`` list, you can enable it by adding
|
||||
``'django.contrib.contenttypes'`` to your ``INSTALLED_APPS`` setting.
|
||||
|
||||
It's generally a good idea to have the contenttypes framework
|
||||
installed; several of Django's other bundled applications require it:
|
||||
|
||||
* The admin application uses it to log the history of each object
|
||||
added or changed through the admin interface.
|
||||
|
||||
* Django's `authentication framework`_ uses it to tie user permissions
|
||||
to specific models.
|
||||
|
||||
* Django's comments system (``django.contrib.comments``) uses it to
|
||||
"attach" comments to any installed model.
|
||||
|
||||
.. _authentication framework: ../authentication/
|
||||
|
||||
The ``ContentType`` model
|
||||
=========================
|
||||
|
||||
Each instance of ``ContentType`` has three fields which, taken
|
||||
together, uniquely describe an installed model:
|
||||
|
||||
``app_label``
|
||||
The name of the application the model is part of. This is taken from
|
||||
the ``app_label`` attribute of the model, and includes only the *last*
|
||||
part of the application's Python import path;
|
||||
"django.contrib.contenttypes", for example, becomes an ``app_label``
|
||||
of "contenttypes".
|
||||
|
||||
``model``
|
||||
The name of the model class.
|
||||
|
||||
``name``
|
||||
The human-readable name of the model. This is taken from
|
||||
`the verbose_name attribute`_ of the model.
|
||||
|
||||
Let's look at an example to see how this works. If you already have
|
||||
the contenttypes application installed, and then add `the sites
|
||||
application`_ to your ``INSTALLED_APPS`` setting and run ``manage.py
|
||||
syncdb`` to install it, the model ``django.contrib.sites.models.Site``
|
||||
will be installed into your database. Along with it a new instance
|
||||
of ``ContentType`` will be created with the following values:
|
||||
|
||||
* ``app_label`` will be set to ``'sites'`` (the last part of the Python
|
||||
path "django.contrib.sites").
|
||||
|
||||
* ``model`` will be set to ``'site'``.
|
||||
|
||||
* ``name`` will be set to ``'site'``.
|
||||
|
||||
.. _the verbose_name attribute: ../model-api/#verbose_name
|
||||
.. _the sites application: ../sites/
|
||||
|
||||
Methods on ``ContentType`` instances
|
||||
====================================
|
||||
|
||||
Each ``ContentType`` instance has methods that allow you to get from a
|
||||
``ContentType`` instance to the model it represents, or to retrieve objects
|
||||
from that model:
|
||||
|
||||
``get_object_for_this_type(**kwargs)``
|
||||
Takes a set of valid `lookup arguments`_ for the model the
|
||||
``ContentType`` represents, and does `a get() lookup`_ on that
|
||||
model, returning the corresponding object.
|
||||
|
||||
``model_class()``
|
||||
Returns the model class represented by this ``ContentType``
|
||||
instance.
|
||||
|
||||
For example, we could look up the ``ContentType`` for the ``User`` model::
|
||||
|
||||
>>> from django.contrib.contenttypes.models import ContentType
|
||||
>>> user_type = ContentType.objects.get(app_label="auth", model="user")
|
||||
>>> user_type
|
||||
<ContentType: user>
|
||||
|
||||
And then use it to query for a particular ``User``, or to get access
|
||||
to the ``User`` model class::
|
||||
|
||||
>>> user_type.model_class()
|
||||
<class 'django.contrib.auth.models.User'>
|
||||
>>> user_type.get_object_for_this_type(username='Guido')
|
||||
<User: Guido>
|
||||
|
||||
Together, ``get_object_for_this_type`` and ``model_class`` enable two
|
||||
extremely important use cases:
|
||||
|
||||
1. Using these methods, you can write high-level generic code that
|
||||
performs queries on any installed model -- instead of importing and
|
||||
using a single specific model class, you can pass an ``app_label``
|
||||
and ``model`` into a ``ContentType`` lookup at runtime, and then
|
||||
work with the model class or retrieve objects from it.
|
||||
|
||||
2. You can relate another model to ``ContentType`` as a way of tying
|
||||
instances of it to particular model classes, and use these methods
|
||||
to get access to those model classes.
|
||||
|
||||
Several of Django's bundled applications make use of the latter
|
||||
technique. For example, `the permissions system`_ in Django's
|
||||
authentication framework uses a ``Permission`` model with a foreign
|
||||
key to ``ContentType``; this lets ``Permission`` represent concepts
|
||||
like "can add blog entry" or "can delete news story".
|
||||
|
||||
.. _lookup arguments: ../db-api/#field-lookups
|
||||
.. _a get() lookup: ../db-api/#get-kwargs
|
||||
.. _the permissions system: ../authentication/#permissions
|
||||
|
||||
The ``ContentTypeManager``
|
||||
--------------------------
|
||||
|
||||
``ContentType`` also has a custom manager, ``ContentTypeManager``,
|
||||
which adds the following methods:
|
||||
|
||||
``clear_cache()``
|
||||
Clears an internal cache used by ``ContentType`` to keep track of which
|
||||
models for which it has created ``ContentType`` instances. You probably
|
||||
won't ever need to call this method yourself; Django will call it
|
||||
automatically when it's needed.
|
||||
|
||||
``get_for_model(model)``
|
||||
Takes either a model class or an instance of a model, and returns the
|
||||
``ContentType`` instance representing that model.
|
||||
|
||||
The ``get_for_model`` method is especially useful when you know you
|
||||
need to work with a ``ContentType`` but don't want to go to the
|
||||
trouble of obtaining the model's metadata to perform a manual lookup::
|
||||
|
||||
>>> from django.contrib.auth.models import User
|
||||
>>> user_type = ContentType.objects.get_for_model(User)
|
||||
>>> user_type
|
||||
<ContentType: user>
|
||||
|
||||
Generic relations
|
||||
=================
|
||||
|
||||
Adding a foreign key from one of your own models to ``ContentType``
|
||||
allows your model to effectively tie itself to another model class, as
|
||||
in the example of the ``Permission`` model above. But it's possible to
|
||||
go one step further and use ``ContentType`` to enable truly generic
|
||||
(sometimes called "polymorphic") relationships between models.
|
||||
|
||||
A simple example is a tagging system, which might look like this::
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes import generic
|
||||
|
||||
class TaggedItem(models.Model):
|
||||
tag = models.SlugField()
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_object = generic.GenericForeignKey('content_type', 'object_id')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.tag
|
||||
|
||||
A normal ``ForeignKey`` can only "point to" one other model, which
|
||||
means that if the ``TaggedItem`` model used a ``ForeignKey`` it would have to
|
||||
choose one and only one model to store tags for. The contenttypes
|
||||
application provides a special field type --
|
||||
``django.contrib.contenttypes.generic.GenericForeignKey`` -- which
|
||||
works around this and allows the relationship to be with any
|
||||
model. There are three parts to setting up a ``GenericForeignKey``:
|
||||
|
||||
1. Give your model a ``ForeignKey`` to ``ContentType``.
|
||||
|
||||
2. Give your model a field that can store a primary-key value from the
|
||||
models you'll be relating to. (For most models, this means an
|
||||
``IntegerField`` or ``PositiveIntegerField``.)
|
||||
|
||||
3. Give your model a ``GenericForeignKey``, and pass it the names of
|
||||
the two fields described above. If these fields are named
|
||||
"content_type" and "object_id", you can omit this -- those are the
|
||||
default field names ``GenericForeignKey`` will look for.
|
||||
|
||||
This will enable an API similar to the one used for a normal ``ForeignKey``;
|
||||
each ``TaggedItem`` will have a ``content_object`` field that returns the
|
||||
object it's related to, and you can also assign to that field or use it when
|
||||
creating a ``TaggedItem``::
|
||||
|
||||
>>> from django.contrib.models.auth import User
|
||||
>>> guido = User.objects.get(username='Guido')
|
||||
>>> t = TaggedItem(content_object=guido, tag='bdfl')
|
||||
>>> t.save()
|
||||
>>> t.content_object
|
||||
<User: Guido>
|
||||
|
||||
Reverse generic relations
|
||||
-------------------------
|
||||
|
||||
If you know which models you'll be using most often, you can also add
|
||||
a "reverse" generic relationship to enable an additional API. For example::
|
||||
|
||||
class Bookmark(models.Model):
|
||||
url = models.URLField()
|
||||
tags = generic.GenericRelation(TaggedItem)
|
||||
|
||||
``Bookmark`` instances will each have a ``tags`` attribute, which can
|
||||
be used to retrieve their associated ``TaggedItems``::
|
||||
|
||||
>>> b = Bookmark('http://www.djangoproject.com/')
|
||||
>>> b.save()
|
||||
>>> t1 = TaggedItem(content_object=b, tag='django')
|
||||
>>> t1.save()
|
||||
>>> t2 = TaggedItem(content_object=b, tag='python')
|
||||
>>> t2.save()
|
||||
>>> b.tags.all()
|
||||
[<TaggedItem: django>, <TaggedItem: python>]
|
||||
|
||||
If you don't add the reverse relationship, you can do the lookup manually::
|
||||
|
||||
>>> b = Bookmark.objects.get(url='http://www.djangoproject.com/)
|
||||
>>> bookmark_type = ContentType.objects.get_for_model(b)
|
||||
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id,
|
||||
... object_id=b.id)
|
||||
[<TaggedItem: django>, <TaggedItem: python>]
|
||||
|
||||
Note that if you delete an object that has a ``GenericRelation``, any objects
|
||||
which have a ``GenericForeignKey`` pointing at it will be deleted as well. In
|
||||
the example above, this means that if a ``Bookmark`` object were deleted, any
|
||||
``TaggedItem`` objects pointing at it would be deleted at the same time.
|
@ -951,6 +951,23 @@ Example::
|
||||
|
||||
If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary.
|
||||
|
||||
``iterator()``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Evaluates the ``QuerySet`` (by performing the query) and returns an
|
||||
`iterator`_ over the results. A ``QuerySet`` typically reads all of
|
||||
its results and instantiates all of the corresponding objects the
|
||||
first time you access it; ``iterator()`` will instead read results and
|
||||
instantiate objects in discrete chunks, yielding them one at a
|
||||
time. For a ``QuerySet`` which returns a large number of objects, this
|
||||
often results in better performance and a significant reduction in
|
||||
memory use.
|
||||
|
||||
Note that using ``iterator()`` on a ``QuerySet`` which has already
|
||||
been evaluated will force it to evaluate again, repeating the query.
|
||||
|
||||
.. _iterator: http://www.python.org/dev/peps/pep-0234/
|
||||
|
||||
``latest(field_name=None)``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -178,7 +178,8 @@ A date field. Has a few extra optional arguments:
|
||||
====================== ===================================================
|
||||
|
||||
The admin represents this as an ``<input type="text">`` with a JavaScript
|
||||
calendar and a shortcut for "Today."
|
||||
calendar, and a shortcut for "Today." The JavaScript calendar will always start
|
||||
the week on a Sunday.
|
||||
|
||||
``DateTimeField``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
@ -10,18 +10,21 @@ Cookies contain a session ID -- not the data itself.
|
||||
Enabling sessions
|
||||
=================
|
||||
|
||||
Sessions are implemented via a piece of middleware_ and a Django model.
|
||||
Sessions are implemented via a piece of middleware_.
|
||||
|
||||
To enable session functionality, do these two things:
|
||||
To enable session functionality, do the following:
|
||||
|
||||
* Edit the ``MIDDLEWARE_CLASSES`` setting and make sure
|
||||
``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``.
|
||||
The default ``settings.py`` created by ``django-admin.py startproject`` has
|
||||
``SessionMiddleware`` activated.
|
||||
|
||||
* Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting, and
|
||||
run ``manage.py syncdb`` to install the single database table that stores
|
||||
session data.
|
||||
* Add ``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting,
|
||||
and run ``manage.py syncdb`` to install the single database table
|
||||
that stores session data.
|
||||
|
||||
**New in development version**: this step is optional if you're not using
|
||||
the database session backend; see `configuring the session engine`_.
|
||||
|
||||
If you don't want to use sessions, you might as well remove the
|
||||
``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'``
|
||||
@ -29,6 +32,44 @@ from your ``INSTALLED_APPS``. It'll save you a small bit of overhead.
|
||||
|
||||
.. _middleware: ../middleware/
|
||||
|
||||
Configuring the session engine
|
||||
==============================
|
||||
|
||||
**New in development version**.
|
||||
|
||||
By default, Django stores sessions in your database (using the model
|
||||
``django.contrib.sessions.models.Session``). Though this is convenient, in
|
||||
some setups it's faster to store session data elsewhere, so Django can be
|
||||
configured to store session data on your filesystem or in your cache.
|
||||
|
||||
Using file-based sessions
|
||||
-------------------------
|
||||
|
||||
To use file-based sessions, set the ``SESSION_ENGINE`` setting to
|
||||
``"django.contrib.sessions.backends.file"``.
|
||||
|
||||
You might also want to set the ``SESSION_FILE_PATH`` setting (which
|
||||
defaults to ``/tmp``) to control where Django stores session files. Be
|
||||
sure to check that your web server has permissions to read and write to
|
||||
this location.
|
||||
|
||||
Using cache-based sessions
|
||||
--------------------------
|
||||
|
||||
To store session data using Django's cache system, set ``SESSION_ENGINE``
|
||||
to ``"django.contrib.sessions.backends.cache"``. You'll want to make sure
|
||||
you've configured your cache; see the `cache documentation`_ for details.
|
||||
|
||||
.. _cache documentation: ../cache/
|
||||
|
||||
.. note::
|
||||
|
||||
You probably don't want to use cache-based sessions if you're not using
|
||||
the memcached cache backend. The local memory and simple cache backends
|
||||
don't retain data long enough to be good choices, and it'll be faster
|
||||
to use file or database sessions directly instead of sending everything
|
||||
through the file or database cache backends.
|
||||
|
||||
Using sessions in views
|
||||
=======================
|
||||
|
||||
@ -153,7 +194,18 @@ Here's a typical usage example::
|
||||
Using sessions out of views
|
||||
===========================
|
||||
|
||||
Internally, each session is just a normal Django model. The ``Session`` model
|
||||
The ``SessionStore`` which implements the session storage method can be imported
|
||||
and a API is available to manipulate the session data outside of a view::
|
||||
|
||||
>>> from django.contrib.sessions.engines.db import SessionStore
|
||||
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
|
||||
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
|
||||
>>> s['last_login']
|
||||
datetime.datetime(2005, 8, 20, 13, 35, 0)
|
||||
>>> s.save()
|
||||
|
||||
Or if you are using the ``django.contrib.sessions.engine.db`` each
|
||||
session is just a normal Django model. The ``Session`` model
|
||||
is defined in ``django/contrib/sessions/models.py``. Because it's a normal
|
||||
model, you can access sessions using the normal Django database API::
|
||||
|
||||
@ -245,6 +297,31 @@ Settings
|
||||
|
||||
A few `Django settings`_ give you control over session behavior:
|
||||
|
||||
SESSION_ENGINE
|
||||
--------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
See `configuring the session engine`_ for more details.
|
||||
|
||||
SESSION_FILE_PATH
|
||||
-----------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``/tmp/``
|
||||
|
||||
If you're using file-based session storage, this sets the directory in
|
||||
which Django will store session data.
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
------------------
|
||||
|
||||
|
@ -253,9 +253,14 @@ DATABASE_ENGINE
|
||||
|
||||
Default: ``''`` (Empty string)
|
||||
|
||||
The database backend to use. Either ``'postgresql_psycopg2'``,
|
||||
``'postgresql'``, ``'mysql'``, ``'mysql_old'``, ``'sqlite3'``,
|
||||
``'oracle'``, or ``'ado_mssql'``.
|
||||
The database backend to use. The build-in database backends are
|
||||
``'postgresql_psycopg2'``, ``'postgresql'``, ``'mysql'``, ``'mysql_old'``,
|
||||
``'sqlite3'``, ``'oracle'``, or ``'ado_mssql'``.
|
||||
|
||||
You can also use a database backend that doesn't ship with Django by
|
||||
setting ``DATABASE_ENGINE`` to a fully-qualified path (i.e.
|
||||
``mypackage.backends.whatever``). Writing a whole new database backend from
|
||||
scratch is left as an exercise to the reader.
|
||||
|
||||
DATABASE_HOST
|
||||
-------------
|
||||
@ -728,6 +733,21 @@ Default: ``'root@localhost'``
|
||||
The e-mail address that error messages come from, such as those sent to
|
||||
``ADMINS`` and ``MANAGERS``.
|
||||
|
||||
SESSION_ENGINE
|
||||
--------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``django.contrib.sessions.backends.db``
|
||||
|
||||
Controls where Django stores session data. Valid values are:
|
||||
|
||||
* ``'django.contrib.sessions.backends.db'``
|
||||
* ``'django.contrib.sessions.backends.file'``
|
||||
* ``'django.contrib.sessions.backends.cache'``
|
||||
|
||||
See the `session docs`_ for more details.
|
||||
|
||||
SESSION_COOKIE_AGE
|
||||
------------------
|
||||
|
||||
@ -770,6 +790,17 @@ Default: ``False``
|
||||
Whether to expire the session when the user closes his or her browser.
|
||||
See the `session docs`_.
|
||||
|
||||
SESSION_FILE_PATH
|
||||
-----------------
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
Default: ``/tmp/``
|
||||
|
||||
If you're using file-based session storage, this sets the directory in
|
||||
which Django will store session data. See the `session docs`_ for
|
||||
more details.
|
||||
|
||||
SESSION_SAVE_EVERY_REQUEST
|
||||
--------------------------
|
||||
|
||||
|
@ -555,6 +555,38 @@ template loaders that come with Django:
|
||||
Django uses the template loaders in order according to the ``TEMPLATE_LOADERS``
|
||||
setting. It uses each loader until a loader finds a match.
|
||||
|
||||
The ``render_to_string()`` shortcut
|
||||
===================================
|
||||
|
||||
To cut down on the repetitive nature of loading and rendering
|
||||
templates, Django provides a shortcut function which largely
|
||||
automates the process: ``render_to_string()`` in
|
||||
``django.template.loader``, which loads a template, renders it and
|
||||
returns the resulting string::
|
||||
|
||||
from django.template.loader import render_to_string
|
||||
rendered = render_to_string('my_template.html', { 'foo': 'bar' })
|
||||
|
||||
The ``render_to_string`` shortcut takes one required argument --
|
||||
``template_name``, which should be the name of the template to load
|
||||
and render -- and two optional arguments::
|
||||
|
||||
dictionary
|
||||
A dictionary to be used as variables and values for the
|
||||
template's context. This can also be passed as the second
|
||||
positional argument.
|
||||
|
||||
context_instance
|
||||
An instance of ``Context`` or a subclass (e.g., an instance of
|
||||
``RequestContext``) to use as the template's context. This can
|
||||
also be passed as the third positional argument.
|
||||
|
||||
See also the `render_to_response()`_ shortcut, which calls
|
||||
``render_to_string`` and feeds the result into an ``HttpResponse``
|
||||
suitable for returning directly from a view.
|
||||
|
||||
.. _render_to_response(): ../shortcuts/#render-to-response
|
||||
|
||||
Extending the template system
|
||||
=============================
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user