Skip to content

Instantly share code, notes, and snippets.

@FZambia
Created March 26, 2013 13:41
Show Gist options
  • Save FZambia/5245441 to your computer and use it in GitHub Desktop.
Save FZambia/5245441 to your computer and use it in GitHub Desktop.
django relation between user and object using contenttypes framework
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class RelationManager(models.Manager):
"""
Contains helpful methods for operating with Relation model
"""
def __init__(self, *args, **kwargs):
self.default_relation_type = kwargs.pop('default_relation_type')
super(RelationManager, self).__init__(*args, **kwargs)
def _generate_kwarg_dict(self, content_object, user, relation_type):
"""
Create kwargs to use in manager methods.
"""
if relation_type is None:
relation_type = self.default_relation_type
if isinstance(content_object, models.Model):
ctype = ContentType.objects.get_for_model(content_object)
object_id = getattr(
content_object,
'pk',
getattr(content_object, 'id')
)
elif isinstance(content_object, dict):
content_type_id = content_object['content_type_id']
object_id = content_object['object_id']
ctype = ContentType.objects.get_for_id(content_type_id)
else:
raise Exception('malformed content_object type')
kwargs = {
'content_type': ctype,
'object_id': object_id,
'type': relation_type
}
if user:
if isinstance(user, list):
kwargs['user__in'] = user
else:
kwargs['user'] = user
return kwargs
def get_for_object(self, content_object, relation_type=None):
"""
Find all existing relations for content object.
"""
params = self._generate_kwarg_dict(content_object, None, relation_type)
return self.filter(**params).select_related('user', 'content_type')
def get_for_user_list(self, content_object, user_list, relation_type=None):
"""
Find all existing relations of certain relation type for list of users.
"""
params = self._generate_kwarg_dict(content_object, user_list, relation_type)
return self.filter(**params).select_related('user', 'content_type')
def get_for_user(self, content_object, user, relation_type=None):
"""
Find relation between content_object and user.
Return it if exists. Otherwise return None.
"""
params = self._generate_kwarg_dict(content_object, user, relation_type)
try:
item = self.get(**params)
except Relation.DoesNotExist:
return None
return item
def add_for_user(self, content_object, user, relation_type=None):
"""
Create relation between content_object and user if not exists yet.
"""
params = self._generate_kwarg_dict(content_object, user, relation_type)
obj, created = self.get_or_create(**params)
return obj
def del_for_user(self, content_object, user, relation_type=None):
"""
Delete relation between content_object and user.
"""
params = self._generate_kwarg_dict(content_object, user, relation_type)
return self.filter(**params).delete()
class Relation(models.Model):
"""
Generic relation between user and content object
"""
NOTIFICATIONS = 0
TYPE_CHOICES = (
(NOTIFICATIONS, u'общие уведомления об изменениях объекта'),
)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
user = models.ForeignKey(User, verbose_name=u"пользователь")
type = models.SmallIntegerField(u"тип связи", choices=TYPE_CHOICES, default=NOTIFICATIONS)
created_at = models.DateTimeField(u"создано", auto_now_add=True)
updated_at = models.DateTimeField(u"обновлено", auto_now=True)
objects = RelationManager(default_relation_type=NOTIFICATIONS)
def __unicode__(self):
return u"relation between user {0} and {1}:{2}".format(
self.user.username,
self.content_type.name,
self.object_id
)
class Meta:
verbose_name = "relation"
verbose_name_plural = "relations"
unique_together = ('content_type', 'object_id', 'user', 'type')
ordering = ('created_at',)
get_latest_by = 'id'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment