Django Socketio 101 - django

I try to implement a chat with django-socketio in my django app.
First, I have to learn about django-socketio, so I read the README of https://github.com/stephenmcd/django-socketio
I really want to get the basis of it. So I try to create a simple thing where a message will be rendered through socketio.
My events.py:
#events.on_connect
def first_connect(request, socket, context):
socket.broadcast_channel("my message")
My view:
def chat(request):
return render_to_response('chat.html', {} ,context_instance=RequestContext(request))
My url:
url(r'^chat/$', 'projet.views.chat'),
My html:
<head>
{% load socketio_tags %}
{% socketio %}
<script>
var socket = new.io.Socket();
socket.connect();
socket.on('connect', function(){
socket.subscribe('my_channel');
});
</script>
</head>
When I go to localhost:8000/chat, nothing appear.
So it's probably very basic, but how can I do to simply send a message through my socket and render it in my html when I connect to it?
I really want to learn about it, so if someone has a tutorial about django-sockieto, I would really appreciate it.

You can look at Cody Soyland blog entries here and here. It may be outdated but I think you can get the feeling of what should be going on there. Also it's not about django-socketio.

Related

Load a template with Django and React JS with a single GET call

I am building an application with Django as the backend and React js for making the interface of the application.
I have a set of Posts which I want to display.
Currently, the approach which I am following is -
Get the template having the compiled js code linked to it.
Then again make get call to get the posts
My question is - In this current approach I am making 2 GET calls to the backend, one for rendering the template and then again for getting the Post.
What is the best way to achieve this? Is this the usual flow how applications are built using Django and React JS?
First off: I don't see anything wrong with doing this in two requests, because one loads the application itself and the second loads the content. To me this seperation makes sense and might turn out to be useful in the future if you want to reuse say the Endpoint, that yields the the posts(i.e. the content).
Answering your question: If, for whatever reason, you absolutely want to load everything with a single GET, a good way of doing so, would be to pass a list of posts to the context as a JSON-serialized object and then load these into the JS-context within the Django-template.
i.e. in the view.py:
from json import dumps
def view(request):
context = {
'posts':get_posts(),
}
render_to_response('django_template.html', context,
context_instance=RequestContext(request))
def get_posts():
qs = Posts.objects.all()
return dumps({'posts': qs })
in the django_template:
{% block content %}
<div id="root"></div>
{% endblock %}
{% block javascript %}
<script>
var INITIAL_POSTS = {{ posts|safe }};
</script>
<script type="text/javascript"
src="PATH_TO_STATIC_REACT_ASSET.JS"></script>
{% endblock %}
you should now have your posts in your JS context and can load them in your React component. Once again: I would agree with Daniel Rosemans comment

Doing auto redirect using CherryPy

I've just discovered CherryPy. I am going through the tutorial, so far so good. While doing it I wanted to create a "BUSY DOING WORK" splash screen, essentially I have a python function that for example updates an sqlite table with 10000 records. What I want to do is get CherryPy to display a busy.html page while the database is being updated, when the database operation completes I want to redirect the user back to the main.html page.
So far I have only come across
dev update_db(self):
#Code to update the database goes here
return "busy.html"<----show user that work is being done
#database has completed
CherryPy.redirect "main.html"
But return simply exits the function. Is there anyway of doing presenting the user with a temporary splashscreen, while the database is being updated then returning the user back to another page once its complete.
I suppose an alternative is to have a message flash across the top of the existing page, But I don't know if CherryPy has a flash message feature much like Flask.
IMHO, you can achieve this with generators and here is a link from latest (v3.8) cherrypy documentation. However, you should take into account the following issue in the docs
Streaming generators are sexy, but they play havoc with HTTP. CherryPy allows you to stream output for specific situations: pages which take many minutes to produce, or pages which need a portion of their content immediately output to the client. Because of the issues outlined above, it is usually better to flatten (buffer) content rather than stream content. Do otherwise only when the benefits of streaming outweigh the risks.
Generators have some limitations as written in the documentation
you cannot manually modify the status or headers within your page handler if that handler method is a streaming generator, because the method will not be iterated over until after the headers have been written to the client. This includes raising exceptions like HTTPError, NotFound, InternalRedirect and HTTPRedirect. To use a streaming generator while modifying headers, you would have to return a generator that is separate from (or embedded in) your page handler.
Because the headers have already been written to the client when streaming, raising redirection exception cannot help to redirect to different page after your long running task. If I were you, I would yield this
<meta http-equiv="refresh" content="0;URL='/anotherpage'" />
or this at the final yield
<script>window.location.href="/anotherpage";</script>
I coded and example for you. I hope this gives you an idea.
# encoding: utf-8
import time
import cherrypy
class Root(object):
#cherrypy.expose
def index(self):
content = '''<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("body").append("<p>jQuery Ready</p>");
setTimeout(function(){
$("body").html("Redirecting Please Wait...")
}, 2500);
});
</script>
</head>
<body>
<p>Page Content1</p>
<p>Page Content2</p>
<p>Page Content3</p>
<p>Page Content4</p>
<p>Page Content5</p>
<p>Page Content Final</p>
</body>
</html>
'''
for line in content.split("\n"):
yield line
time.sleep(1)
else:
yield '''<meta http-equiv="refresh" content="5;URL='/anotherpage'" />'''
index._cp_config = {'response.stream': True}
#cherrypy.expose
def anotherpage(self):
return "Another Page"
cherrypy.quickstart(Root(), "/")

Getting checkbox value in flask

I'm trying to poll the state of checkboxes (this is done in JS every three seconds). This solution returns "None" (see code below); Both printouts (with 'args' and with 'form') return "None". I'm expecting True/False, depending on the checkbox's boolean state.
index.html:
{% extends "layout.html" %}
{% block content %}
<div id="results" class="container">{{data_load|safe}}</div>
<input id='testName' type='checkbox' value='Yes' name='testName'>
{% endblock %}
and the relevant flask app snippet:
#app.route('/', methods = ['GET', 'POST'])
def index():
return render_template('index.html', data_load=timertry())
#app.route('/_timertry', methods = ['GET', 'POST'])
def timertry():
print request.args.get('testName')
print request.form.get('testName')
return "some html going into 'results' div.."
The JavaScript polling function (adapted from here):
$(document).ready(function() {
$.ajaxSetup({cache : false});
setInterval(function() {
$('#results').load('/_timertry?' + document.location );
}, 3000); // milliseconds!
});
This should be simple enough, but none of the SO solutions I looked into (e.g., using jquery, adapting the flask/ajax example, etc.) worked.
EDIT: following mark's suggestion (including the javascript) and adding
print request.values in index.html returns (seen on the console in Aptana):
CombinedMultiDict([ImmutableMultiDict([]), ImmutableMultiDict([])])
Clearly, the request seems empty. The post request is logged (when checkbox is pressed) as:
127.0.0.1 - - [03/Oct/2013 00:11:44] "POST /index HTTP/1.1" 200 -
Any ideas here?
Your javascript does the following every three seconds...
$('#results').load('/_timertry?' + document.location);
In other words, you are using the jQuery load() function. The documentation for that function states that this will, in essence, call an HTTP get request to the URL you provide as the parameter (something like /_timertry?http://www.example.org. In other words, a GET request will be called to /timertry?http://www.example.org, which will be handled by Flask's timertry method.
When you have an HTTP form, and you click the "Submit" button, the browser does some magic to push all of the values to the server in the request. When you just do a simple AJAX request, none of that happens for you. Instead, you need to explicitly state what you want to be passed as data to the server (although there are plugins to help you with "post the values of an HTML form using AJAX").
So, because at no point did you do anything in your Javascript to retrieve the value of checkbox to include it into the AJAX request, the AJAX request has no values specifying that the checkbox was checked. You would need to have jQuery check if the box is checked...
var isChecked = $('#testName').is(':checked');
# Now do something with isChecked...
From what I can tell, however, you are sort of misusing HTTP: the load function will make a GET request, and you probably want something to happen as a request of the request. You probably want to make it do a POST request instead (see here and here). Also, you mentioned that you're looking for something to post when a value is changed. Putting this together, you can do something like this...
// Ensure that the function is called when the DOM is ready...
$(function() {
// Register an event that should be fired when the checkbox value is changed
$('#testName').change(function() {
var data = { isChecked : $(this).is(':checked') };
$.post('/', data);
});
})
In this case, we have an event that is called when a checkbox is checked, and that event causes us to make a POST request to the server.
I'm going to answer this question which was found in the comments of the question
"which becomes a question of how to submit a form without a 'submit' button.."
So it is very possible to submit a value when a user clicks on the button
{% block content %}
<form id="target" action="YourViewName">
<div id="results" class="container">{{ data_load|safe }}</div>
<input id='testName' type='checkbox' value='Yes' name='testName'>
</form>
{% endblock %}
$( "#results" ).click(function() {
$( "#target" ).submit();
});
If you want to stay on the same page, however, you're going to need to use an ajax call to pass the data back rather then use a standard submit, however This tutorial covers that topic fairly well. but a basic change to send the data back would look like
$( "#results" ).click(function() {
var request = $.ajax({
type: "POST",
url: "/YourViewName",
data: {'input_value':$('#testName').val()},
dataType: "html"
}).done(function(msg) {
// I don''t know what you want to do with a return value...
// or if you even want a return value
}
});
and the flask would look like
#app.route("/YourViewName")
def example():
list_name = request.args.get("input_value")
#if you don't want to change the web page just give a blank return
return ""

Django partial template responses

Is it considered correct/ are there any pitfalls in returning partial templates to ajax POST requests?
For example:
if request.is_ajax:
# response is just the form
return render(request, 'contact/fields.html', {'form':form})
The most typical approach is returning JSON and then contructing whatever HTML you need client-side from the JSON data. However, it could be argued that this is mixing presentation with behavior and it would be better to clearly separate out the HTML.
On the flip-side, returning a block of HTML is about as polar-south of "RESTful" as you can get. In pure REST philosophy, the views should return data in a standard and reusable container (such as JSON or XML). Later if you needed to pull the form into an iOS/Android/WP7/etc. app environment rather than a webpage, the JSON/XML will serve you just as well, whereas the HTML is virtually useless.
I can easily see both arguments, and I don't think one is necessarily more right than the other. Ultimately, I think you just have to do what works best for your app and what "feels right" to you. Think in terms of what is more maintainable and extensible for your particular circumstances.
I have no yet tried this with form POST request but very similarly we return partial HTML to AJAX GET request to do page changes without loading the whole page. I think it would work well for form request as well (we are in fact debating at the moment whether to use this approach on a page with multiple different forms).
I think if done right it is not a bad design pattern. We accomplish this by changing which base template is extended based on whether it was an AJAX call.
A simplified example:
### view
base_template = "base.html"
if request.is_ajax():
base_template = "base-ajax.html"
return render_to_response(request, 'page.html', {'base_template': base_template})
### page.html
{% extends base_template %}
{% block main %}new page content{% endblock %}
### base.html
<html>
<!-- complete html page -->
...
{% block main %}this is what changes per page{% endblock %}
...
</html>
### base-ajax.html
{% block main %}this is what changes per page{% endblock %}
I think most of my ajax return responses return DOM elements and not the entire form.
(an example)
...
person = ''' {1} {2}'''.format(p.id, p.first_name, p.last_name)
q = simplejson.dumps({"person":person})
return HttpResponse(q, mimetype="application/json")
The above sends back a simple DOM element to the template and inserts it into a table at the bottom. Sliding in right to left.
If you send back the entire template, the entire screen will flash and won't get any slick animations. That is my understanding anyway.
I have done this for a couple of jQuery Dialogs. The dialog contents are requested by a AJAX request, the contents are rendered on server side and then returned and displayed. So far I have experienced no problems with that.
From personal experience i can say that there is no pitfalls. I just not very good design pattern (not good practice). I used to do that on pretty high loaded project.
I have had the same problem in the year 2023 (question was asked in 2012..). Django still doesn't support rendering a template without invoking the whole chain of template inheritance.
So here's a basic way of rendering partial template:
from django.template import Context, loader
def render_template_to_string(template_name, context=None):
template = loader.get_template(template_name).template
context_instance = Context(context or {})
with context_instance.bind_template(template):
return template.nodelist.render(context_instance)
And your (partial) template can be as simple as:
<ul>my partial list
{% for opt in options %}
<li>{{ opt }}</li>
{% endfor %}
</ul>
You then invoke it by e.g.
from django.http import HttpResponse
resp = render_template_to_string(
"path/to/partial/html", {"options": range(10)}
)
return HttpResponse(resp)
FYI you might want to add support for some node exclusions, error handling, or better flexibility of what gets passed to render_template_to_string.

Can I use Socket.IO with Django? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Is there any way to use Socket.IO http://socket.io/ with Django?
Sure you can!
Django itself arent asyncronous so you have to use a Socket.IO server in parallel with your normal django server, node.js isnt always a good choice but there exists others written in pure python.
here is a blog/tutorial that uses gevent as socket.io server.
http://codysoyland.com/2011/feb/6/evented-django-part-one-socketio-and-gevent/
For a similar solution that has a bit more history you can look at Orbited, (www.orbited.org)
I am asking does a server side django implementation exist for node.js in django.
No. node.js is its own language running in its own interpreter. However if you are asking if there is a Django app which allows communicating with a Socket.IO client, then yes and no. No because no pre-made solution currently exists, and yes because all the parts you need to implement it already exist.
To implement the protocol with django, check out Django-Websocket for the backend websocket server, Ajax libraries from Dajax Project and Socket.IO-rack which is a ruby gem which implements the protocol and ruby is close enough in structure to django that you can get a lot of inspiration from it.
Start here:
http://gevent-socketio.readthedocs.org
and here:
https://github.com/abourget/gevent-socketio
There are some Django examples as to how to get started.
It is based on Gevent, which implements a cooperative concurrency model. It's great coming from a request/response world, as it adds some callbacks and micro-threads without imposing it massively on your workflow.
Try it out :)
I think the best way to asyncronous communication with Django is have a node server listening in another port and use the api client of Socket.io. In this way, you aren't depend of the support of the modules for django and is very simple: Node listening the request from client, convert this request in a post request and send to Django for the port which listen Django.
Is the best way i think.
server.js
var http = require('http');
var server = http.createServer().listen(3000);
var io = require('socket.io').listen(server);
var querystring = require('querystring');
io.on('connection',function(socket) {
console.log('Connected to the client');
socket.on('new comment',function(data) {
console.log('Web--->Node');
var values = querystring.stringify(data);
console.log(values);
var options = {
hostname:'localhost',
port:'8000',
path:'/create-comment',
method:'POST',
headers:{
'Content-Type':'application/x-www-form-urlencoded',
'Content-Length':values.length
}
};
var request = http.request(options, function(response) {
response.setEncoding('utf8');
response.on('data',function(data){
//Here return django
console.log('Django-->Node');
io.emit('return comment',data);
});
});
request.write(values);
request.end();
});
});
views.py
def trysock(request):
print 'In tryshok'
comments = Comment.objects.all()
dic = {
'name': 'User',
'form': CommentForm(),
'comments': comments
}
return render(request,'index.html',dic)
#csrf_exempt
def create_comment(request):
print 'Django<---Node'
Comment.objects.create(
user = request.POST['user'],
comment = request.POST['comment']
)
response = JsonResponse({'user' : request.POST['user'], 'comment' : request.POST['comment']})
print response.content
return HttpResponse(response.content)
index.html
<div class='col-md-12'>
<div class='col-md-6'>
<form method='POST'>
{% csrf_token %}
{{form.comment}}
<button id='boton'>Comentar</button>
</form>
</div>
<div id='comentarios' class='col-md-6'>
{% for comment in comments %}
<p>{{ comment.user }} - {{ comment.comment}}</p>
{% endfor %}
</div>
</div>
<!-- Fin Formulario comentarios -->
</div>
<script>
var socket = io.connect('http://localhost:3000');
console.log(socket);
$('#boton').on('click', Comentar);
function Comentar(e) {
console.log('Comentar(e)')
e.preventDefault();
var datos = {
user:"user",
comment : 'comment'
};
socket.emit('nuevo comentario', datos);
console.log('Enviando....: ' + datos.user + '-' + datos.comment);
}
socket.on('devolviendo comentario', function(data) {
console.log('Recibiendo...');
var dato = JSON.parse(data);
$('#comentarios').prepend('<p>' + dato.user + '-' + dato.comment + '</p>')
});
</script>
For an example of using socket.io with django, you might want to look at django-serverpush. It integrates django with socket.io as the transport and tornado/tornandio2 as the async server instead of node.js
https://github.com/hamax/django-serverpush
Other have used django with node.js+socket.io with rabbitMQ as the message queue bridge between the two. There was a talk, "Real-Time Django" at djangocon 2011 which described usng this approach for large real-time (award-show-type) applications.
Guys there is no solid support for socket.io with django... there is how ever easy toy program support g-event socket.io support was dropped for the last year as well, django-socket.io is also abandoned.
If you want to build a simple toy program using django-socket.io and or g-event socket.io sure, but anything that scales is unlikely "https://github.com/ryesoft/gevent-socketio" this is experimental.
Issues with more than 1 worker with gunicorn....
https://github.com/abourget/gevent-socketio/issues/112
The work around is this commit.
https://github.com/getpenelope/gevent-socketio/commit/6c80c17705c9a1b3adcb0f99abde1c4d369c337b
I thought it would throw it out there just incase someone was trying to use this in a production environment like my self.