The default [http://www.djangoproject.com/documentation/sessions/ SessionMiddleware] that comes with Django lets you pick if you want all sessions to be browser-length or persistent, if you want to use different types of sessions based on a users preference (e.g. the good old "Remember Me" check-box) you're gonna have to write your own middleware. Fortunately it's pretty easy, this page documents my attempt, I don't like the "!DualSession" name much, but it's the best I could come up with. {{{ #!python from django.conf import settings from django.contrib.sessions.models import Session from django.utils.cache import patch_vary_headers import datetime class DualSessionMiddleware(object): """Session middleware that allows you to turn individual browser-length sessions into persistent sessions and vice versa. This middleware can be used to implement the common "Remember Me" feature that allows individual users to decide when their session data is discarded. If a user ticks the "Remember Me" check-box on your login form create a persistent session, if they don't then create a browser-length session. This middleware replaces SessionMiddleware, to enable this middleware: - Add this middleware to the MIDDLEWARE_CLASSES setting in settings.py, replacing the SessionMiddleware entry. - In settings.py add this setting: PERSISTENT_SESSION_KEY = 'sessionpersistent' - Tweak any other regular SessionMiddleware settings (see the sessions doc), the only session setting that's ignored by this middleware is SESSION_EXPIRE_AT_BROWSER_CLOSE. Once this middleware is enabled all sessions will be browser-length by default. To make an individual session persistent simply do this: session[settings.PERSISTENT_SESSION_KEY] = True To make a persistent session browser-length again simply do this: session[settings.PERSISTENT_SESSION_KEY] = False """ def process_request(self, request): 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 # those changes and set a session cookie. patch_vary_headers(response, ('Cookie',)) try: modified = request.session.modified except AttributeError: pass else: if modified or settings.SESSION_SAVE_EVERY_REQUEST: session_key = request.session.session_key or Session.objects.get_new_session_key() if not request.session.get(settings.PERSISTENT_SESSION_KEY, False): # session will expire when the user closes the browser max_age = None expires = None else: max_age = settings.SESSION_COOKIE_AGE expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S 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, max_age = max_age, expires = expires, domain = settings.SESSION_COOKIE_DOMAIN, secure = settings.SESSION_COOKIE_SECURE or None) return response }}} I think the class doc provides all the installation and deployment info you'll need (just make sure you read the Django docs about [http://www.djangoproject.com/documentation/middleware/ middleware] first). Here's a sample login view that makes use of this middleware to implement the "Remember Me" check-box. {{{ #!python from django.contrib import auth from django.contrib.auth import REDIRECT_FIELD_NAME from django.http import HttpResponseRedirect from mysite.accounts.forms import LoginForm def login(request): """Display and processs the login form.""" no_cookies = False account_disabled = False invalid_login = False redirect_to = request.REQUEST.get(REDIRECT_FIELD_NAME, '') if request.method == 'POST': if request.session.test_cookie_worked(): request.session.delete_test_cookie() form = LoginForm(request.POST) if form.is_valid(): user = auth.authenticate(username = form.cleaned_data['username'], password = form.cleaned_data['password']) if user: if user.is_active: auth.login(request, user) request.session[settings.PERSISTENT_SESSION_KEY] = form.cleaned_data['remember_user'] # login successful, redirect return HttpResponseRedirect('/') else: account_disabled = True else: invalid_login = True else: no_cookies = True form = None else: form = LoginForm() # cookie must be successfully set/retrieved for the form to be processed request.session.set_test_cookie() return render_to_response('accounts/login.html', { 'no_cookies': no_cookies, 'account_disabled': account_disabled, 'invalid_login': invalid_login, 'form': form, REDIRECT_FIELD_NAME: redirect_to }, context_instance = RequestContext(request)) }}} And here's the sample login form used by the view. {{{ #!python from django import newforms as forms from django.newforms import widgets from django.contrib.auth.models import User class LoginForm(forms.Form): """Login form for users.""" username = forms.RegexField(r'^[a-zA-Z0-9_]{1,30}$', max_length = 30, min_length = 1, error_message = 'Must be 1-30 alphanumeric characters or underscores.') password = forms.CharField(min_length = 6, max_length = 128, widget = widgets.PasswordInput, label = 'Password') remember_user = forms.BooleanField(required = False, label = 'Remember Me') def clean(self): try: user = User.objects.get(username__iexact = self.cleaned_data['username']) except User.DoesNotExist, KeyError: raise forms.ValidationError('Invalid username, please try again.') if not user.check_password(self.cleaned_data['password']): raise forms.ValidationError('Invalid password, please try again.') return self.cleaned_data }}} If you've noticed anything that could be done better please point it out. This hasn't been tested in production yet, so you should run your own tests to make sure everything is working as expected.[[BR]][[BR]] ---- Comment: The !LoginForm needs individual clean_username and clean_password functions since the clean function will get called regardless of validation errors in the fields. A too short username or password will cause that key to be missing in cleaned_data, and clean will throw a !KeyError. [wiki:CookBookMiddlewares Other Middleware]