Node. js and Socket. IO extend Django's real-time processing functions
This article mainly introduces the use of Node. js and Socket. i/O extends Django's real-time processing function. The real-time asynchronous processing function is quite powerful. The example given in this article is to create a real-time chat room. For more information, see
Today, our goal is to use Django, Redis, and Socket. IO to create a real-time chat room. Although almost all Web applications can create a chat room. This article tells you how to convert a REST-based application into a real-time Web application at a high level. I will use Django to create the REST part. In fact, it is free to use any comfortable language/framework. Next, let's jump into the code and list what we need first.
Composition:
Django 1.4 +
Redis 2.6.x (optional, but recommended)
Redis-py 2.7.x (only required when you use Redis)
Node. js v0.8.x
Socket. IO v0.9.x
Cookie v0.0.5
Databases, sqlite, and others that you think are similar to databases
Your version may be different from mine. I have not tested other versions yet, and all of them use the latest stable version. If you cannot install it using the following method, I have compiled the Ubuntu software package. You can get other operating system versions from the comments.
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 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 |
Let's start with Django Project
?
1 2 3 |
Django-admin.py startproject realtime_tutorial & cd realtime_tutorial Python manage. py startapp core Mkdir nodejs |
After the preceding code is executed, the django project is configured. The next step is to set the database in the settings file. Create a blank database first. (This is an example of setting file. Add a "core" in my app and configure the templates and urls paths. You can modify the configuration information in settings at will, but it must correspond to your app.
Model
Models is simple. We will create a table containing user and text. If you want to make it more complex, you can add information such as chatroom. (For the sake of simplicity, only two are written here)
?
1 2 3 4 5 6 |
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) |
This is the model we will use. Next we will execute the following syncdb Code (the first line of code) to create a database. Then create several users for testing. (Line 2 code)
?
1 2 3 4 |
Python manage. py syncdb Python manage. py createsuperuser Node Server With Socket. IO |
This section describes how to send and obtain real-time information. Use Node. js to create an app server that depends on Socket. IO, and use Redis for this task. Create a file named "chat. js" in the nodejs dictionary and put it here:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
Var http = require ('http '); Var server = http. createServer (). listen (4000 ); Var io = require ('socket. io '). listen (server ); Var cookie_reader = require ('cooker '); Var querystring = require ('querystring '); Var redis = require ('socket. io/node_modules/redis '); Var sub = redis. createClient (); // Subscribe to chat channel Sub. subscribe ('chat '); // Configure socket. io to store the cookie set by Django 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 ){ // Send the information from Redis to the client Sub. on ('message', function (channel, message ){ Socket. send (message ); }); // The client sends messages through 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 } }; // Use Django server to send messages Var req = http. get (options, function (res ){ Res. setEncoding ('utf8 '); // Output error message Res. on ('data', function (message ){ If (message! = 'Everything worked :)'){ Console. log ('message: '+ Message ); } }); }); Req. write (values ); Req. end (); }); }); |
First, import and create an http server to listen to port localhost 4000. Then subscribe to Redis's "chat" chanel. Finally, we only need to call it in Django view.
Last time we set the Django setting where Socket. IO can use cookies in the local field, which allows us to access cookie data through socket. handshake. cookie. How can we get the user's session.
We set Socket. i/O cookies can only be held after many events. The first event is the Redis release channel. When our users notice that a new message has been notified that it will send a message to clients on all sites.
Another event is that when the client sends a message through Socket. IO, we use the string query module to create a query to be sent to our Django service. Our Django service will run on the local port 3000, but you can change that requirement. Set the path to the/node_api URL. We will soon create it next to Django. Once queryString is sent, Django will save the relevant components and return "Everything worked (all working)" to us )". If no output error is returned to us, close the node console.
A node that does not use Redis
You really don't have to use Redis for this project. I found it will be a good learning experience. If you want to divert Redis, you can create a channel, use expressions or some other class libraries, the code above will receive a message from Django. When a comment is saved, you can use Socket. add comments to all clients for IO
Template
This is where all of our HTML and javascript are placed. It allows us to display comments and interact with our Node service.
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<! 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> |
On the above page, we use socket. IO to connect to our node service on the local port 4000. When we get an information from the server, we will perform some escaping in the directory and add it to our annotation list, when we want to send a message, we will perform a corresponding 13 (press the next key) key check on the input box. Once it is pressed, we send a message to the server to make it held. Once it is saved by Django to our database, we will get a "message" event to add it to our session List.
Our Django shows that we will load a "comments" variable in the next step, so we set and traverse all the following loops in that way. This part is only used when the page is initially loaded. Our javascript will add data to this directory as a new data from our Node service.
View
Open realtime_tutorial/core/views. py and edit it like me:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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: # Get the user through sessionid 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) # Create Comment Comments. objects. create (user = user, text = request. POST. get ('comment ')) # Send it to the chat room after creation R = redis. StrictRedis (host = 'localhost', port = 6379, db = 0) R. publish ('chat', user. username + ':' + request. POST. get ('comment ')) Return HttpResponse ("Everything worked :)") Except t Exception, e: Return HttpResponseServerError (str (e )) |
Let's see what happened here. Home is a standard view File. Use select_related to obtain the username of each comment, instead of returning a comment query set when the page is loaded for the first time.
The second is the view of the information sent by the Node app. We get the sessionid from POST, and then get the userid through decoding. After confirming that the user exists, you can create a comment. Now, send username and comment to the Redis server. Finally, send the data to the channel called "chat.
URLs
This is relatively simple, because we will use the views and template that comes with Django.
?
1 2 3 4 5 6 7 8 |
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!
Open servers.
?
1 2 3 4 |
Python manage. py runserver localhost: 3000 # In a new terminal tab cd into the nodejs directory we created earlier Node chat. js |
I put the code on github. If you want to make it better, you can allow users to create and join chat rooms. You can also use PHP or Rails for development.