搜索
首页后端开发Python教程使用Node.js和Socket.IO扩展Django的实时处理功能

 今天,我们的目标是使用Django,Redis,和Socket.IO建立一个实时的聊天室。虽然几乎所有的Web应用程序都可以建立一个聊天室的。这篇文章将以较高的水平告诉你如何将基于REST的应用程序转换成一个实时的Web应用程序的。我会使用Django创建REST的部分,实际上自由地使用任何你舒服的语言/框架均可。接下来,让我们跳进代码,先列举我们所需要的部分。

组成:

  •     Django 1.4+
  •     Redis 2.6.x (版本可选,但是建议使用)
  •     Redis-py 2.7.x (仅当你使用Redis时需要)
  •     Node.js v0.8.x
  •     Socket.IO v0.9.x
  •     Cookie v0.0.5
  •     数据库、sqlite、其他你觉得类似数据库形式的 均可


 

你的使用的版本可能与我不同,我暂时未测试其他版本,全部使用当前最新稳定版本。如果你无法通过下面方法安装,我已经编译好Ubuntu的软件包。你可以从评论中得到其他操作系统版本情况。
 

#https://docs.djangoproject.com/en/dev/topics/install/
sudo apt-get install python-pip
sudo pip install django
 
#http://redis.io/download
sudo apt-get install redis-server
 
#https://github.com/andymccurdy/redis-py
sudo pip install redis  
   
#https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs
 
#https://github.com/LearnBoost/socket.io
npm install socket.io
 
#https://github.com/shtylman/node-cookie
npm install cookie

让我们从Django Project开始
 

django-admin.py startproject realtime_tutorial && cd realtime_tutorial
python manage.py startapp core
mkdir nodejs

执行完以上的代码,django project就配置好了,接下来要做的是在settings文件中设置数据库。先创建一个空白数据库。(这是一个settings file的例子。在我的app中添加了一个“core”然后配置templates和urls的路径。你可以随意更改settings中的配置信息,但是要与你的app相对应。

Model

models很简单,我们将要建一个包含user和text的表。如果你想让他更复杂一些,可以添加chatroom等信息。(为了简单起见,这里只写了两个)
 

from django.db import models
from django.contrib.auth.models import User
 
class Comments(models.Model):
  user = models.ForeignKey(User)
  text = models.CharField(max_length=255)

这就是我们将要使用的model,接下来执行下面的syncdb代码(第一行代码),创建数据库。然后创建几个user来测试。(第二行代码)

python manage.py syncdb
python manage.py createsuperuser
 
Node Server With Socket.IO

这一部分将要介绍实时信息的发送和获取。使用Node.js创建一个依赖Socket.IO的app server,使用Redis 来做这项苦差事。在nodejs字典中,创建一个叫做“chat.js”的文件,然后把它放在这里:
 

var http = require('http');
var server = http.createServer().listen(4000);
var io = require('socket.io').listen(server);
var cookie_reader = require('cookie');
var querystring = require('querystring');
 
var redis = require('socket.io/node_modules/redis');
var sub = redis.createClient();

 
//订阅chat channel


sub.subscribe('chat');

 
//配置socket.io来存储Django设置的cookie
io.configure(function(){
  io.set('authorization', function(data, accept){
    if(data.headers.cookie){
      data.cookie = cookie_reader.parse(data.headers.cookie);
      return accept(null, true);
    }
    return accept('error', false);
  });
  io.set('log level', 1);
});
 
io.sockets.on('connection', function (socket) {
   
  //把信息从Redis发送到客户端
  sub.on('message', function(channel, message){
    socket.send(message);
  });
   
  //客户端通过socket.io发送消息
  socket.on('send_message', function (message) {
    values = querystring.stringify({
      comment: message,
      sessionid: socket.handshake.cookie['sessionid'],
    });
     
    var options = {
      host: 'localhost',
      port: 3000,
      path: '/node_api',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': values.length
      }
    };
     
    //使用Django server发消息
    var req = http.get(options, function(res){
      res.setEncoding('utf8');
       
      //输出错误信息
      res.on('data', function(message){
        if(message != 'Everything worked :)'){
          console.log('Message: ' + message);
        }
      });
    });
     
    req.write(values);
    req.end();
  });
});

首先,我们导入并创建http server来监听localhost 4000端口。然后订阅Redis的 "chat" chanel。最后,只要我们在Django view中调用就可以了。


上次我们设置了Socket.IO能在本地领域使用cookie的那个Django设置,这能让我们通过socket.handshake.cookie去访问cookie数据。能让我们怎样得到用户的session会话。

我们设置Socket.IO的cookies之后我们才能持有很多事件,第一个事件是Redis 发布通道,当我们的用户注意到一个新的消息已经被通知它将发送消息给所有站点的客户端。

另一个事件是当客户端通过Socket.IO发送一个信息,我们使用字符串查询(queryString)模块去创建一个query查询才能被发送到我们的Django服务。我们的Django服务在本地端口3000将会运行但你能改变了那个需求。路径设置成/node_api那个URL我们将不久创建在Django旁边。一旦我们发送queryString我们等待的Django就会保存相关组件并给我们返回"Everything worked(都在工作)"。如果我们没有得到返回给我们的输出错误就关闭节点控制台


一个关于不使用Redis的节点

你真的完全没必要为这项目使用Redis,我发现它将是一个好的学习体验,如果你想分流Redis你可以创建一个通道,使用表达式或一些其它类库,在这上面的代码会从Django里接收一个消息当一个注释被保存时,然后你能通过Socket.IO添加注释给所有的客户端
模板

这就是我们所有HTML和javascript被放置的地方,它允许我们显示注释和交互我们的Node服务
 

<!DOCTYPE html>
<html>
<head>
 <title>Realtime Django</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script>
 <script src="http://localhost:4000/socket.io/socket.io.js"></script>
 <script>
  $(document).ready(function(){
   var socket = io.connect('localhost', {port: 4000});
    
   socket.on('connect', function(){
    console.log("connect");
   });
    
   var entry_el = $('#comment');
        
   socket.on('message', function(message) {
    //Escape HTML characters
    var data = message.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
     
    //Append message to the bottom of the list
    $('#comments').append('<li>' + data + '</li>');
    window.scrollBy(0, 10000000000);
    entry_el.focus();
   });
           
   entry_el.keypress(function(event){
    //When enter is pressed send input value to node server
    if(event.keyCode != 13) return;
    var msg = entry_el.attr('value');
    if(msg){
      socket.emit('send_message', msg, function(data){
        console.log(data);
      });
     
    //Clear input value 
    entry_el.attr('value', '');
    }
   });
  });
 </script>
</head>
<body>
  <ul id="comments">
    {% for comment in comments %}
      <li>{{comment.user}}: {{comment.text}}</li>
    {% endfor %}
  </ul>
  <input type="text" id="comment" name="comment" />
</body>
</html>


在上面我们用socket.IO在本地端口4000连接我们的节点服务。当从服务器得到了一个信息我们就在目录和添加它到我们注释列表里做了些转义,当我们想要发送一个信息我们就对输入盒子里做了相应的13(按下一个键)的按键检查。一旦那被按下后我们就发出信息给服务器使其被持有。一旦它被Django保存到我们的数据库我们就得到一个"message"事件将其添加到我们的会话列表里

我们的Django显示我们在下一步将加载一个"comments"变量,因此我们那样设置并遍历下面所有的循环。这部分仅仅是当页面初始加载时使用了,我们的javascript将添加数据给这个目录作为一个新的数据来自我们的Node服务

View

打开realtime_tutorial/core/views.py,然后像我一样编辑:
 

from core.models import Comments, User
 
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseServerError
from django.views.decorators.csrf import csrf_exempt
from django.contrib.sessions.models import Session
from django.contrib.auth.decorators import login_required
 
import redis
 
@login_required
def home(request):
  comments = Comments.objects.select_related().all()[0:100]
  return render(request, 'index.html', locals())
 
@csrf_exempt
def node_api(request):
  try:
    #通过sessionid获得 user
    session = Session.objects.get(session_key=request.POST.get('sessionid'))
    user_id = session.get_decoded().get('_auth_user_id')
    user = User.objects.get(id=user_id)
 
    #创建Comment
    Comments.objects.create(user=user, text=request.POST.get('comment'))
     
    #创建后就把它发送到聊天室
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    r.publish('chat', user.username + ': ' + request.POST.get('comment'))
     
    return HttpResponse("Everything worked :)")
  except Exception, e:
    return HttpResponseServerError(str(e))

让我们看看这里发生了什么。home是一个标准的view文件。使用select_related来获得每一个comment的username,而不是在页面第一次加载的时候,就返回一个comment的query集合。

第二个就是我们Node app发送信息的view。我们从POST中获取sessionid,然后通过解码获得userid。确定user存在后,就可以创建comment了。现在吧username 和 comment 发送到 Redis server。最后,把数据发送到这里叫做"chat"的频道。

URLs

这里比较简单,因为我们将要使用Django自带的views和template。
 

from django.conf.urls import patterns, include, url
 
urlpatterns = patterns('',
  url(r'^$', 'core.views.home', name='home'),
  url(r'^node_api$', 'core.views.node_api', name='node_api'),
  url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'admin/login.html'}, name='login'),
  url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout'),
)

Start It Up!

打开servers。
 

python manage.py runserver localhost:3000
 
#In a new terminal tab cd into the nodejs directory we created earlier
node chat.js

我把代码放到github。如果你想把它做得更好,就允许user创建、加入聊天室。你也可以使用PHP或者Rails开发。

如果你有什么问题,请在评论处写下或联系我。

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Python vs. C:了解关键差异Python vs. C:了解关键差异Apr 21, 2025 am 12:18 AM

Python和C 各有优势,选择应基于项目需求。1)Python适合快速开发和数据处理,因其简洁语法和动态类型。2)C 适用于高性能和系统编程,因其静态类型和手动内存管理。

Python vs.C:您的项目选择哪种语言?Python vs.C:您的项目选择哪种语言?Apr 21, 2025 am 12:17 AM

选择Python还是C 取决于项目需求:1)如果需要快速开发、数据处理和原型设计,选择Python;2)如果需要高性能、低延迟和接近硬件的控制,选择C 。

达到python目标:每天2小时的力量达到python目标:每天2小时的力量Apr 20, 2025 am 12:21 AM

通过每天投入2小时的Python学习,可以有效提升编程技能。1.学习新知识:阅读文档或观看教程。2.实践:编写代码和完成练习。3.复习:巩固所学内容。4.项目实践:应用所学于实际项目中。这样的结构化学习计划能帮助你系统掌握Python并实现职业目标。

最大化2小时:有效的Python学习策略最大化2小时:有效的Python学习策略Apr 20, 2025 am 12:20 AM

在两小时内高效学习Python的方法包括:1.回顾基础知识,确保熟悉Python的安装和基本语法;2.理解Python的核心概念,如变量、列表、函数等;3.通过使用示例掌握基本和高级用法;4.学习常见错误与调试技巧;5.应用性能优化与最佳实践,如使用列表推导式和遵循PEP8风格指南。

在Python和C之间进行选择:适合您的语言在Python和C之间进行选择:适合您的语言Apr 20, 2025 am 12:20 AM

Python适合初学者和数据科学,C 适用于系统编程和游戏开发。1.Python简洁易用,适用于数据科学和Web开发。2.C 提供高性能和控制力,适用于游戏开发和系统编程。选择应基于项目需求和个人兴趣。

Python与C:编程语言的比较分析Python与C:编程语言的比较分析Apr 20, 2025 am 12:14 AM

Python更适合数据科学和快速开发,C 更适合高性能和系统编程。1.Python语法简洁,易于学习,适用于数据处理和科学计算。2.C 语法复杂,但性能优越,常用于游戏开发和系统编程。

每天2小时:Python学习的潜力每天2小时:Python学习的潜力Apr 20, 2025 am 12:14 AM

每天投入两小时学习Python是可行的。1.学习新知识:用一小时学习新概念,如列表和字典。2.实践和练习:用一小时进行编程练习,如编写小程序。通过合理规划和坚持不懈,你可以在短时间内掌握Python的核心概念。

Python与C:学习曲线和易用性Python与C:学习曲线和易用性Apr 19, 2025 am 12:20 AM

Python更易学且易用,C 则更强大但复杂。1.Python语法简洁,适合初学者,动态类型和自动内存管理使其易用,但可能导致运行时错误。2.C 提供低级控制和高级特性,适合高性能应用,但学习门槛高,需手动管理内存和类型安全。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),