django项目之SNS社交平台开发(模拟新浪微博)
本节内容
- 项目介绍
- 架构设计
- 表结构设计
- 图片本地预览功能
- 项目详细功能实现
1. 项目介绍
新浪weibo是一个用来练习开发能力的非常好的项目,本节我们一起来开发一个简单版的weibo
1.1功能需求
- 一个人可以follow很多人
- 一个用户如果发了新weibo会自动推送所有关注他的人
- 可以搜索、关注其它用户
- 可以分类关注
- 用户可以发weibo, 转发、收藏、@其它人
- 发微博时可选择公开、隐私、只能好友看等
- 可私信聊天
- 热门微博无需关注
- 我的微博列表
- 可以评论、点赞微博
- 发微博时可以上传图片、视频、可以发表情
2. 架构设计
2.1 设计架构前需要考虑的问题
- 1.图片的本地预览、异步上传技术,上文已有叙述(详见下文);
- 2.当用户发布微博后,需要立即告诉用户已经发布成功,并在前端展示,可是新浪微博同一时间可能有上千用户发微博,也就是说短时间内需要做大量的数据库操作,这就需要用户等很长时间,这样就没有完美的用户体验,那么这个问题该如何解决呢?
解决方案:当用户发布微博,上传图片至临时目录,微博内容放入rabbitmq,前端获取微博内容和图片地址,立即生成新微博,并告诉用户微博发布成功。事实上,此时微博只是放入了rabbitmq,并没有存入数据库,也就是说只要用户的微博放入rabbitmq,就算用户发新微博成功。然后后台其他模块从rabbitmq取消息并存入数据库。
- 3.用户发送微博后,需要将该微博推送给他的所有关注者,而用户同时可上传多张图片和视频,目前一张高清图片大约10M左右,假设用户每次上传3张图片,共30M,需要将30M推送给所有粉丝,大家都知道新浪微博中一个明星可能有几千万粉丝,以姚晨为例,姚晨有7000多万粉丝,那么问题来了,难道我们要将这30M内容存入每一个粉丝的数据库表里吗?这样下去,新浪微博短短几分钟就需要大量的存贮空间,如何解决这个问题呢?
解决方案:推送给粉丝微博时,仍然推送姚晨对应表的数据即可,粉丝那里存微博id即可,这样就解决了存贮问题。
- 4.如问题3所示,姚晨有7000多万粉丝,我们真的需要推送给那么多人吗?那又需要做多少数据库操作,服务器压力也会很大,那么如何解决这个问题呢?
解决方案:新浪微博是怎么做的呢?这里我们可以筛选有效用户进行推送,那么什么是有效用户呢?如果一个用户很长时间没有登录,那么我们推送给他也没有意义,这里我们定义有效用户即活跃用户,即用户24小时内有登录过。经过筛选,姚晨的7000多万粉丝可能只需要推送其中的一千万即可,这样大大减小了服务器的压力。
- 5.如何判断用户是否是活跃用户呢?
解决方案:当用户登陆的时候,我们以用户id作为key值,Ture作为value值存入缓存radis,并设置超时时间为24小时,每次推送前会判断radis里是否含有当前用户id,如果有,则推送。
- 6.如何实现接口安全?
详细点击右侧链接:如何实现接口安全?
2.2 架构实现
所需服务组件:
- django: 用户页面呈现
- nginx: 前端高并发必备
- cdn:异地高并发、静态内容速度快必备
- redis: 热点weibo\话题数据高效存储
- rabbitMQ: 用户weibo推送
- SOA:服务解耦,服务接口化
- zabbix,nagios: 系统监控
- google analysis: 用户访问质量、行为分析监控
用户发微博流程图

3.表结构设计
from django.db import models from django.contrib.auth.models import User # Create your models here. class Weibo(models.Model): '''所有微博''' wb_type_choices = ( (0,'new'), (1,'forward'), (2,'collect'), ) wb_type = models.IntegerField(choices=wb_type_choices,default=0) forward_or_collect_from = models.ForeignKey('self',related_name="forward_or_collects",blank=True,null=True) user = models.ForeignKey('UserProfile') text = models.CharField(max_length=140) pictures_link_id = models.CharField(max_length=128,blank=True,null=True) video_link_id = models.CharField(max_length=128,blank=True,null=True) perm_choice = ((0,'public'), (1,'private'), (2,'friends')) perm = models.IntegerField(choices=perm_choice,default=0) date = models.DateTimeField(auto_now_add=True) def __str__(self): return self.text class Topic(models.Model): '''话题''' name = models.CharField(max_length=140) date = models.DateTimeField() def __str__(self): return self.name class Category(models.Model): '''微博分类''' name = models.CharField(max_length=32) def __str__(self): return self.name class Comment(models.Model): '''评论''' to_weibo = models.ForeignKey(Weibo) p_comment = models.ForeignKey('self',related_name="child_comments") user = models.ForeignKey('UserProfile') comment_type_choices = ((0,'comment'),(1,'thumb_up')) comment_type = models.IntegerField(choices=comment_type_choices,default=0) comment = models.CharField(max_length=140) date = models.DateTimeField(auto_created=True) def __str__(self): return self.comment class Tags(models.Model): '''标签''' name = models.CharField(max_length=64) def __str__(self): return self.name class UserProfile(models.Model): '''用户信息''' user = models.OneToOneField(User) name = models.CharField(max_length=64) brief = models.CharField(max_length=140,blank=True,null=True) sex_type = ((1,'Male'),(0,'Female')) sex = models.IntegerField(choices=sex_type,default=1) age = models.PositiveSmallIntegerField(blank=True,null=True) email = models.EmailField() tags = models.ManyToManyField(Tags) head_img = models.ImageField() follow_list = models.ManyToManyField('self',blank=True,related_name="my_followers",symmetrical=False) #registration_date = models.DateTimeField(auto_created=True) def __str__(self): return self.name
4.上传图片本地预览功能
如下图,发微博时,可以同时发图片,图片我们肯定是通过ajax异步上传到后台,但是我只是从电脑里选择了图片后,我还想实现一个在本地小图预览的功能, 这个需求如何实现呢?

有的同学会立刻想到,把图片先传到后台服务器,然后返回一个img url, 在当前浏览器上就可以调用这个用img url预览了,这样是没问题的。 但是这是最好的办法么?如果我上传的图片非常大,比如说5mb,网速又慢,那我可能2分钟后才能看到预览, 用户体验必然不好, 有没有办法可以实现在图片还没上传完就可以预览呢?
本地预览实现
function handleFileSelect(evt) { var files = evt.target.files; // Loop through the FileList and render image files as thumbnails. for (var i = 0, f; f = files[i]; i++) { // Only process image files. if (!f.type.match('image.*')) { continue; } var reader = new FileReader(); // Closure to capture the file information. reader.onload = (function(theFile) { return function(e) { // Render thumbnail. var span = document.createElement('span'); span.innerHTML = [ '<img style="height: 75px; border: 1px solid #000; margin: 5px" src="', e.target.result, '" title="', escape(theFile.name), '"/>' ].join(''); document.getElementById('list').insertBefore(span, null); }; })(f); // Read in the image file as a data URL. reader.readAsDataURL(f); } } document.getElementById('files').addEventListener('change', handleFileSelect, false);
<input type="file" id="files" multiple /> <output id="list"></output>
参考 http://stackoverflow.com/questions/14069421/show-an-image-preview-before-upload
4. 协作开发
git 基础教程http://www.runoob.com/git/git-branch.html
5.项目详细功能实现
目录结构:


浙公网安备 33010602011771号