Skip to content

Instantly share code, notes, and snippets.

@mmalone
Created September 1, 2009 20:06
Show Gist options
  • Save mmalone/179338 to your computer and use it in GitHub Desktop.
Save mmalone/179338 to your computer and use it in GitHub Desktop.
class FriendDescriptor(object):
"""
A descriptor that provides access to a user's friends.
"""
def __get__(self, instance, cls):
if not instance:
raise AttributeError('Manager must be accessed via instance')
Relationship = get_model('friends', 'Relationship')
class RelationshipManager(models.Manager):
def get_query_set(self):
User = get_model('twitterauth', 'User')
return User._default_manager.filter(follower_relationships__user=instance,
follower_relationships__reciprocal=True)
def request(self, user):
rel, created = Relationship.objects.get_or_create(user=instance, to_user=user)
if not created and rel.declined:
# If there's an existing declined request make it not declined so it
# appears again.
rel.declined = False
rel.save()
def decline(self, user):
try:
relationship = user.following_relationships.get(to_user=instance)
relationship.declined = True
relationship.save()
except ObjectDoesNotExist:
pass
def remove(self, user):
try:
relationship = instance.following_relationships.get(to_user=user)
relationship.delete()
except ObjectDoesNotExist:
pass
return RelationshipManager()
def get_friend_request_queryset(superclass, to_user):
class FriendRequestQuerySet(superclass):
def _get_friend_request(self, user):
return FriendRequest(user, to_user)
def get(self, *args, **kwargs):
return self._get_friend_request(super(FriendRequestQuerySet, self).get(*args, **kwargs))
def latest(self, *args, **kwargs):
return self._get_friend_request(super(FriendRequestQuerySet, self).latest(*args, **kwargs)
def __getitem__(self, k):
if isinstance(k, slice):
# If it's a slice we're returning a new queryset
qs = super(FriendRequestQuerySet, self).__getitem__(k)
if isinstance(qs, (list, tuple)):
# If the qs has already been executed then the slice operation
# returns a list and we need to convert the list items, else
# it returns a new qs and we can just duck punch it to be the
# proper type.
return [self._get_friend_requests(i) for i in qs]
qs.__class__ = self.__class__
return qs
return self._get_friend_request(super(FriendRequestQuerySet, self).__getitem__(*args, **kw
def __iter__(self):
superiter = super(FriendRequestQuerySet, self).__iter__()
while True:
yield self._get_friend_request(superiter.next())
return FriendRequestQuerySet
class FriendRequestDescriptor(object):
"""
A descriptor that provides access to a user's friend requests.
"""
def __get__(self, instance, cls):
if not instance:
raise AttributeError('Manager must be accessed via instance')
User = get_model('twitterauth', 'User')
class FriendRequestManager(User._default_manager.__class__):
def get_query_set(self):
qs = User._default_manager.filter(following_relationships__to_user=instance,
following_relationships__reciprocal=False,
following_relationships__declined=False)
qs.__class__ = get_friend_request_queryset(qs.__class__, instance)
return qs
return FriendRequestManager()
from managers import FriendDescriptor
class User(models.Model):
username = models.CharField(max_length=40)
email = models.EmailField()
friends = FriendDescriptor()
friend_requests = FriendRequestDescriptor()
class Relationship(models.Model):
user = models.ForeignKey('twitterauth.User', related_name='following_relationships')
to_user = models.ForeignKey('twitterauth.User', related_name='follower_relationships')
reciprocal = models.BooleanField(default=False)
declined = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True, default=datetime.datetime.now)
modified = models.DateTimeField(auto_now=True, default=datetime.datetime.now)
def __unicode__(self):
return u'%s => %s%s' % (self.user_id, self.to_user_id, ('', ' [mutual]')[self.reciprocal])
class Meta:
unique_together = (('user', 'to_user'))
class FriendRequest(models.Model):
def __init__(self, user, to_user):
self.user = user
self.to_user = to_user
def accept(self):
self.to_user.friends.request(self.user)
def decline(self):
self.to_user.friends.decline(self.user)
def relationship_save(sender, instance, **kwargs):
try:
reciprocal_rel = Relationship.objects.get(user=instance.to_user, to_user=instance.user)
reciprocal_rel.reciprocal = True
reciprocal_rel.declined = False
reciprocal_rel.save()
instance.reciprocal = True
_add_frempties(instance.to_user, instance.user)
_add_frempties(instance.user, instance.to_user)
except Relationship.DoesNotExist:
pass
models.signals.pre_save.connect(relationship_save, sender=Relationship, dispatch_uid=relationship_save.__name__)
def relationship_delete(sender, instance, **kwargs):
try:
reciprocal_rel = Relationship.objects.get(user=instance.to_user, to_user=instance.user)
reciprocal_rel.reciprocal = False
reciprocal_rel.declined = True
reciprocal_rel.save()
_remove_frempties(instance.to_user, instance.user)
_remove_frempties(instance.user, instance.to_user)
except Relationship.DoesNotExist:
pass
models.signals.post_delete.connect(relationship_delete, sender=Relationship, dispatch_uid=relationship_delete.__name__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment