mercredi 13 août 2014

python - Django Database Design pour les flux d'activités sociales - Stack Overflow


I'm trying to implement something like a Facebook timeline or social activity feed where different activities of Users are presented in according to the time of their occurrence. For instance, Someone updated his status and then the same person followed someone else. So, he should be able to see his own actions in reverse chronological order.


I'm still a noob in Django with very little knowledge in python, So I've no idea what's the BEST WAY to do this.


So far I've been able to achieve this using Mixins. Here's what I was doing till now:


class UserActivity(models.Model):
user = models.ForeignKey(User, related_name='related_%(app_label)s_%(class)s')

created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)

slug = models.SlugField(editable=False)

class Meta:
abstract = True


class Status(UserActivity):
"""
Maintain Status History
"""
status = models.CharField(max_length=512)

class Meta:
verbose_name_plural = 'Statuses'
get_latest_by = 'modified'

class Follow(UserActivity):
"""
Track User's Follow Activity
"""
follow = models.ForeignKey(User)

class Meta:
get_latest_by = 'modified'

class StatusMixin(object):
@property
def status(self):
if not hasattr(self, '_status'):
_status = Status.objects.filter(user=self.user)
return _status

class FollowMixin(object):
@property
def follow(self):
if not hasattr(self, '_follow'):
_follow = Follow.objects.filter(user=self.user)
return _follow

class Profile(FollowMixin, StatusMixin, models.Model):
"""
For storing more info of user like birthday, gender, status, avatar
not available in django.contrib.auth.models.User
"""
user = models.OneToOneField(User)

avatar = models.ImageField(upload_to='avatar', blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
gender = models.CharField(max_length=1, choices=[('M', 'Male'), ('F', 'Female')])

def activity(self):
activities = list()
for attr in dir(self):
try:
if isinstance(self.__getattribute__(attr), QuerySet):
activities += self.__getattribute__(attr)
except AttributeError as e:
print(attr, 'Exception: ', e)

sorted_activities = sorted(activities, key=lambda p: p.modified, reverse=True)
return sorted_activities

Problem with this approach is that for small database it will work fine, but what if I have millions or billions of data? How can I paginate the activities?


So while looking for these questions I came across Proxy Models that can definitely solve my problem for now. But one thing worries me about this approach is that all the user data(follows, status, and many more activities) will be stored in same database that will make this particular table grow very fast, this will probably result in bad performance one data starts growing. Maybe, this last thought is silly but I would like to get an answer for that as well.


So, Finally what should be my approach?



  • Keep using Mixins?

  • Proxy Models?

  • Use JOINS?

  • Copying all my activities to a separate table, so that if a want to get only status I won't have to filter out other activities?


Any help will be appreciated. Thanks in Advance :)



I'm trying to implement something like a Facebook timeline or social activity feed where different activities of Users are presented in according to the time of their occurrence. For instance, Someone updated his status and then the same person followed someone else. So, he should be able to see his own actions in reverse chronological order.


I'm still a noob in Django with very little knowledge in python, So I've no idea what's the BEST WAY to do this.


So far I've been able to achieve this using Mixins. Here's what I was doing till now:


class UserActivity(models.Model):
user = models.ForeignKey(User, related_name='related_%(app_label)s_%(class)s')

created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)

slug = models.SlugField(editable=False)

class Meta:
abstract = True


class Status(UserActivity):
"""
Maintain Status History
"""
status = models.CharField(max_length=512)

class Meta:
verbose_name_plural = 'Statuses'
get_latest_by = 'modified'

class Follow(UserActivity):
"""
Track User's Follow Activity
"""
follow = models.ForeignKey(User)

class Meta:
get_latest_by = 'modified'

class StatusMixin(object):
@property
def status(self):
if not hasattr(self, '_status'):
_status = Status.objects.filter(user=self.user)
return _status

class FollowMixin(object):
@property
def follow(self):
if not hasattr(self, '_follow'):
_follow = Follow.objects.filter(user=self.user)
return _follow

class Profile(FollowMixin, StatusMixin, models.Model):
"""
For storing more info of user like birthday, gender, status, avatar
not available in django.contrib.auth.models.User
"""
user = models.OneToOneField(User)

avatar = models.ImageField(upload_to='avatar', blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
gender = models.CharField(max_length=1, choices=[('M', 'Male'), ('F', 'Female')])

def activity(self):
activities = list()
for attr in dir(self):
try:
if isinstance(self.__getattribute__(attr), QuerySet):
activities += self.__getattribute__(attr)
except AttributeError as e:
print(attr, 'Exception: ', e)

sorted_activities = sorted(activities, key=lambda p: p.modified, reverse=True)
return sorted_activities

Problem with this approach is that for small database it will work fine, but what if I have millions or billions of data? How can I paginate the activities?


So while looking for these questions I came across Proxy Models that can definitely solve my problem for now. But one thing worries me about this approach is that all the user data(follows, status, and many more activities) will be stored in same database that will make this particular table grow very fast, this will probably result in bad performance one data starts growing. Maybe, this last thought is silly but I would like to get an answer for that as well.


So, Finally what should be my approach?



  • Keep using Mixins?

  • Proxy Models?

  • Use JOINS?

  • Copying all my activities to a separate table, so that if a want to get only status I won't have to filter out other activities?


Any help will be appreciated. Thanks in Advance :)


0 commentaires:

Enregistrer un commentaire