Hardware, programming and astronomy tutorials and reviews.
Facebook wall like application in Django - part 1
Creating Facebook Wall-like or Twitter-like Django application for small social, intranet or collaboration sites. Part 1 - playing with models and queries.
Facebook is the leading social website and it's functionality or user interface is well known. Many smaller websites try to reuse ideas from Facebook to provide users with UI that they know and which is easy to use and functional. Designing a social site, collaboration web application or company intranet sites we can think about adding a microblog Twitter-like or Facebook Wall-like application. Lets do some initial implementation in Django.
So let say we want to make a company user Wall application. Users are grouped in departments/categories and we want to let users post messages to friends, department workers, public and private messages. Also multimedia handling is required - post a URL and the wall will generate for example YT clip player. Lets start with user profile models:
classDepartment(models.Model):""" Department model """title=models.CharField(max_length=255,verbose_name=_('Name'),blank=True)slug=models.SlugField(max_length=255,unique=True,verbose_name=_('Slug'))def__str__(self):returnself.titledef__unicode__(self):returnself.titleclassMeta:verbose_name=_('Department')verbose_name_plural=_('Departments')classProfile(models.Model):""" User Profile """user=models.ForeignKey(User,unique=True,verbose_name=_('User'),related_name='user')image=models.ImageField(upload_to='user_images',verbose_name=_('Avatar'),blank=True,null=True)dep=models.ForeignKey(Department,verbose_name=_('Department'))friends=models.ManyToManyField(User,verbose_name=_('Friends'),blank=True,null=True,related_name='friends')last_visit=models.DateTimeField(blank=True,auto_now=True,verbose_name=_('Last visit'))# random profile stuffpublic_email=models.EmailField(max_length=100,verbose_name=_('Public email'),blank=True,null=True)facebook=models.URLField(max_length=100,verbose_name=_('Facebook profile'),blank=True,null=True)goldenline=models.URLField(max_length=100,verbose_name=_('Goldenline profile'),blank=True,null=True)jabber=models.CharField(max_length=100,verbose_name=_('Jabber/GTalk'),blank=True,null=True)skype=models.CharField(max_length=100,verbose_name=_('Skype'),blank=True,null=True)gg=models.IntegerField(verbose_name=_('Gadu Gadu'),blank=True,null=True)bio=models.TextField(verbose_name=_('Bio'),blank=True,null=True)def__str__(self):returnstr(self.user)def__unicode__(self):returnunicode(self.user)classMeta:verbose_name=_('User Profile')verbose_name_plural=_('User Profiles')
We have two models - Department model and the true profile model - "Profile". Most important fields are "Department" and "Friends". Also the profiles have to be generated, updated, but this isn't the point of this article.
As for content models for the wall, lest look at simple multimedia model:
classMedia(models.Model):""" storage for Blip attached medias """TYPES=[('url',_('URL')),('image',_('Image')),('video',_('Video Clip'))]type=models.CharField(max_length=100,verbose_name=_('Type'),choices=TYPES)url=models.CharField(max_length=255,verbose_name=_('Media URL'))text=models.TextField(verbose_name=_('Parsed media text'))classMeta:verbose_name=_('Media')verbose_name_plural=_('Media')def__str__(self):returnself.urldef__unicode__(self):returnself.url
We have tree types of multimedias - links, images, and video clips from YouTube, Vimeo etc. The "text" field will contain ready to display HTML code for given media. For finished application user would enter the URL and by AJAX request the django app would parse the URL (fetch the url) and returned required data (player code, website title, image thumbnail etc.).
Main element of a wall or microblog is the message. We need a message model like this one:
classBlip(models.Model):""" storage for user wall messages """TYPES=[('f',_('Friends')),('d',_('All from my department')),('a',_('All users')),('p',_('Private message'))]message=models.TextField(verbose_name=_('Message'))author=models.ForeignKey(User,verbose_name=_('Author'),related_name='author')# user departmentdep=models.ForeignKey(Department,verbose_name=_('Department'))privacy_type=models.CharField(max_length=100,verbose_name=_('Privacy'),choices=TYPES)# set this if private msgprivate_recipients=models.ManyToManyField(User,verbose_name=_('Recipients of PM'),blank=True,null=True,related_name='private_recipients')# copy from profile if message for friendsmessage_friends=models.ManyToManyField(User,verbose_name=_('Friends at the time of creation'),blank=True,null=True,related_name='message_friends')# if this is a reply to another Blipin_reply_to=models.ForeignKey('self',verbose_name=_('Reply to blip'),blank=True,null=True)date=models.DateTimeField(auto_now_add=True)media=models.ManyToManyField(Media,verbose_name=_('Media'),blank=True,null=True)classMeta:verbose_name=_('Blip')verbose_name_plural=_('Blips')def__str__(self):returnself.messagedef__unicode__(self):returnself.message
So we have "message" field for the text users submits, "author" field to identify him and some fields - "dep" and "message_friends" copied at the time of creation. Those fields will help getting proper messages on a user wall. "privacy_type" fields sets the message privacy. If the message is private then it has to have "private_recipients". Using "in_reply_to" field we can reuse this model for commenting other messages. Main messages will have null for this field.
So how do we show proper set of messages on a user wall? User can see his own messages, public messages, messages from his department or from his friends and also private messages sent to him. This can be done easily using Q class from django.db.models:
@login_requireddefshow_wall(request):""" Show the wall page """p=request.user.get_profile()blips=Blip.objects.filter(# user blipsQ(author=request.user,in_reply_to__isnull=True)|# blips for user departmentQ(privacy_type='d',dep=p.dep,in_reply_to__isnull=True)|# private blips to this userQ(privacy_type='p',private_recipients=request.user,in_reply_to__isnull=True)|# blips from user friendsQ(privacy_type='f',message_friends=request.user,in_reply_to__isnull=True)|# public blipsQ(privacy_type='a',in_reply_to__isnull=True)).order_by('-date')returnrender_to_response('wall/show_wall.html',{'blips':blips},context_instance=RequestContext(request))
Python quick-run for such application is short, but the most effort has to be putted in the user interface including JavaScript and AJAX calls to supporting django views. There isn't any ready full blown UI set for such applications, but there are bits and pieces that we can reuse: