Django:使用Redis PubSub,Node.js和Socket.io的JSON通知

我碰到这篇文章: http : //maxburstein.com/blog/realtime-django-using-nodejs-and-socketio/

哪一个引导我在正确的方向。

我目前有一个iOS前端和一个Django后端。 我使用Gunicorn为前端应用程序提供数据。 我的iOS应用程序和我的支持之间的通信是基于REST的。 我只是来回发送JSON。 我不提供任何网页。 只是JSON响应。

我已经实现了一个简单的发表和评论模型:

class Post(models.Model): user = models.ForeignKey(User) blog = models.CharField(max_length=5000) class Comment(models.Model): comment = models.CharField(max_length=140) user = models.ForeignKey(User) post_id = models.ForeignKey(Post) created_at = models.DateTimeField(auto_now_add=True) 

用户可以使博客文章和其他用户可以评论他们。 所以如果userX有一个博客文章和userY评论。 我想通知userX userY评论他/她的post。

我曾经依靠pyAPNS来通知用户; 一个使用Twisted向APNS发送通知的python包装,但是如果userXclosures了我的应用的推送通知,那么userX将无法接收应用内通知。 所以我运气不好

我只关心应用内通知。 我仍然喜欢userX在应用程序中接收实时更新。

当用户发出POST请求时,Django可以将消息发布到Redis上的频道。 Node.js将订阅该频道,并且socket.io会将其发送给该特定用户。

这里是我的views.py的一个简化版本创build注释对象。 我发送了发表评论的用户的ID,post的ID以及发布博客post的用户的ID。 用户将使用json发送一个请求到这个URL: http : //example.com : 8000/ upload-comment/

 def UploadComment(request): data = json.loads(request.body) redis_server = redis.Redis(host='12.345.678.9', port=6379, db=0, password='mypassword') newComment = Comment() newComment.comment = data['comment'] newComment.user_id = data['user_id'] newComment.post_id = data['post_id'] newComment.save() PostOwner = data['post_owner_id'] #id of the blog post owner # Need to send a notification to PostOwner response_data = [] response_data.append( {'send_notifcation_to': PostOwner 'action': 'comment' 'comment_by': newComment.user.username)} redis_server.publish("notifications", json.dumps(response_data)) return HttpResponse('Request Successful') 

Node.js的实现(根据Max Burstein的文章)

 var http = require('http'); var server = http.createServer().listen(4000); var io = require('socket.io').listen(server); 

这是我得到:(我知道这是相当可悲的,但我留下了很多问题。我怎么能订阅node.js到我从Django发布到远程Redis服务器?有多less客户端可以连接到这个套接字有没有限制?是为每个客户端创build的套接字还是每个客户端在同一个套接字上侦听?我可以通过这个套接字发送json数据到一个特定的客户端吗?我知道这是一个庞大的邮件,但我需要绝望的帮助,如果我不清楚,请让我知道,以便我可以编辑这个问题,谢谢!

我绝对不会为此使用node.js。 你可以用Python来处理websockets,就像Celery或者gevent或者其他的一样。

只需创build一个注册到Redis的线程并监听新消息。

当用户连接时,将套接字放入由用户名称索引的弱值散列值; 当他们的消息到达时,在这个散列中查找目标用户名并发送它。 弱值,因为它在用户断开连接后自行清理。 简单,真的。

我还会使用websocket而不是HTTP-PUT向服务器发送新消息。

看看这里的实施: http : //blog.sneawo.com/blog/2013/02/08/real-time-messaging-in-django-using-node-dot-js-and-redis/

听起来像你应该使用像RabbitMQ http://www.rabbitmq.com/devtools.html有一个node.js实现和更多。

检查出来,它应该让你振作起来:)

我也使用一个叫django-websocket-redis的美妙的库。

虽然它不使用gunicorn,它使用uWSGI,这不应该有太多的开销迁移到。 只要按照文档,他们是相当全面的。

https://django-websocket-redis.readthedocs.org/en/latest/

采取一些你的代码,并用django-websockets-redis实现它:

 ## Make a json representation of your model available. class Comment(models.Model): comment = models.CharField(max_length=140) user = models.ForeignKey(User) post_id = models.ForeignKey(Post) created_at = models.DateTimeField(auto_now_add=True) def as_json(self): return dict( id=self.id, comment=self.comment, created_at=self.created_at.strftime('%m/%d/%Y'), post_id=self.post_id user=self.user ) 

然后,在您的意见中,当提出请求时,将json表示保存到您订阅的redis工具中…您可以在任何地方(无论是序列化程序还是视图)执行此操作,但是我将根据您的情况进行操作。

 def UploadComment(request): data = json.loads(request.body) ## In django-websockets-redis, this portion below is registered in the settings.py file, therefore i am commenting this out. ## redis_server = redis.Redis(host='12.345.678.9', port=6379, db=0, password='mypassword') newComment = Comment() newComment.comment = data['comment'] newComment.user_id = data['user_id'] newComment.post_id = data['post_id'] newComment.save() PostOwner = data['post_owner_id'] #id of the blog post owner # Need to send a notification to PostOwner ## Need to turn this into a string before posting to redis json_comment = str(newComment.as_json()) ## Create a facility based on the PostOwner ID. The PostOwner will always be subscribed to this channel. RedisPublisher(facility=PostOwner, broadcast=True).publish_message(json_comment) return HttpResponse('Request Successful') 

现在,我们已经得到了后端照顾,在前端签证JavaScript,你的用户基于他的user.id订阅设施:

 jQuery(document).ready(function($) { var ws4redis = WS4Redis({ uri: '{{ WEBSOCKET_URI }}{{ PostOwner.id }}?subscribe-broadcast&publish-broadcast&echo', receive_message: receiveMessage, heartbeat_msg: {{ WS4REDIS_HEARTBEAT }} }); // receive a message though the Websocket from the server function receiveMessage(msg) { //This is where you would retrieve the JSON string from the Redis server, and subsequently manipulate the DOM with appends, Toastr Notifications, Etc... }