========================
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/>