Django model mixin to ease stashing objects in the session (eg for deferred registration/login)
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
django_session_stashable
.gitignore
AUTHORS
LICENSE
README
setup.py

README

========================
django_session_stashable
========================

Django model mixin that makes it easy to manage a list of objects associated with the current session, principally for the purposes of implementing deferred registration.

I've written a more detailed walkthrough that may be of interest: <http://tartarus.org/james/diary/2009/07/24/implementing-deferred-registration-with-django>.

This was derived from code I wrote at a <http://devfort.com/>.

Basic use
=========

----------------------------------------------------------------------------
from django.db import models
from django.contrib.auth.models import User
from django_session_stashable import SessionStashable

class MyModel(models.Model, SessionStashable):
	created_by = models.ForeignKey(User, null=True)
	name = models.CharField(max_length=255)
	
	def __unicode__(self):
		return self.name
----------------------------------------------------------------------------

Then you can push an object into the session during a view function:

----------------------------------------------------------------------------
obj = MyModel(name="name")
obj.save()
obj.stash_in_session(request.session)
----------------------------------------------------------------------------

Note that you must save the object to the database; django_session_stashable records the object's pk.

You can retrieve a queryset of objects using a class method:

----------------------------------------------------------------------------
stashed_objects = MyModel.get_stashed_in_session(request.session)
----------------------------------------------------------------------------

Checking whether a given object is stashed
==========================================

You can check whether an object is stashed in the current session:

----------------------------------------------------------------------------
if obj.stashed_in_session(request.session):
	...
----------------------------------------------------------------------------

This will often be used in authorization checks; either you only want to check that, or more commonly you combine it with a check against the creating user. Something like the following:

----------------------------------------------------------------------------
class MyModel(models.Model, SessionStashable):
	def visible_by_this_request(self, request):
		if self.created_by==None:
			return self.stashed_in_session(request.session)
		else:
			return self.created_by == request.user
----------------------------------------------------------------------------

Checking whether any objects are stashed
========================================

If implementing deferred registration, you may want a prominent warning that there are "unsaved" objects attached to the session, encouraging registration (or login) after your users have created something in the system.

----------------------------------------------------------------------------
if MyModel.num_stashed_in_session(request.session):
	...
----------------------------------------------------------------------------

Most commonly, you'll pass that number to your template to switch on a warning block. To make this easy, there's a context processor you can pull in, `django_session_stashable.stashed_object_counts`; you'll need to set `context_count_name` on each stashable model, and the count will appear in the context as that name.

Deferred registration and login
===============================

While you could write a function to find all the objects in the session and mark them as belonging to the new user, it's easier just to call the supplied class method:

----------------------------------------------------------------------------
MyModel.reparent_all_my_session_objects(request.session, user)
----------------------------------------------------------------------------

Note that this assumes that you mark object creation using a created_by field, as in the previous example, or you have set the `creator_field` on your class (see example below).

The `reparent_all_session_objects` function is provided as a convenience; connect it to the `django.contrib.auth.singals.user_logged_in` signal to reparent all stashed objects for all models that inherit from SessionStashable when a user logs in:

----------------------------------------------------------------------------
from django.contrib import auth
from django_session_stashable import reparent_all_session_objects

auth.signals.user_logged_in.connect(reparent_all_session_objects)
----------------------------------------------------------------------------

Getting all objects, whether stashed or owned by a real user
============================================================

As a convenience, there is a class method get_objects_for_request which will return either all objects owned by the authenticated user, or all objects stashed in the session, in that order:

----------------------------------------------------------------------------
def list_view(request):
	return render(
		request,
		'template.html',
		{
			'objects': MyModel.get_objects_for_request(request),
		},
	)
----------------------------------------------------------------------------

There is an assumption that MyModel.objects.filter(...) is the right way to go here; if that isn't true for your app, the code isn't complicated: this simply saves time.

Internals
=========

We store against the session, by default using the key "object_stash". If you don't want to use this, or you want to stash objects of different types against the session, you can change the session_variable setting on your class:

----------------------------------------------------------------------------
class MyModel(models.Model, SessionStashable):
	session_variable = 'mymodel_stash'
	
	created_by = models.ForeignKey(User)
	name = models.CharField(max_length=255)
	
class MySecondModel(models.Model, SessionStashable):
	session_variable = 'mysecondmodel_stash'
	
	created_by = models.ForeignKey(User)
	name = models.CharField(max_length=255)
----------------------------------------------------------------------------

We assume the field that stores the creator is called created_by, but you can change this by setting the creator_field on your class:

----------------------------------------------------------------------------
class MyModel(models.Model, SessionStashable):
	session_variable = 'mymodel_stash'
	creator_field = 'creator'
	
	creator = models.ForeignKey(User)
	name = models.CharField(max_length=255)
----------------------------------------------------------------------------

(These two settings would probably benefit from being turned into Meta attributes or similar, but for now I can't be bothered to figure out the nicest approach.)

James Aylett <http://tartarus.org/james/computers/django/>