Tornado and Django limitations? - django

here is what i've found when reading Tornado Help:
Tornado comes with limited support for WSGI. However, since WSGI does not support non-blocking requests, you cannot use any of the asynchronous/non-blocking features of Tornado in your application if you choose to use WSGI instead of Tornado’s HTTP server. Some of the features that are not available in WSGI applications: #tornado.web.asynchronous, the httpclient module, and the auth module.
what it was interresting "before" reading that is the "auth" module, it will make possible to access to Facebook or Google, it's like OpenID (?), but sadly it will not work on WSGI?!!! so how to make that thing work with Django? on FastCGI?

If you take a look at mixins in tornado.auth module you will see that it requires #asynchronous decorator, which is unavailable in WSGI mode due to synchronous nature of the protocol.
There was some kind of proposition to add asynchronous support to WSGI, but I believe it was not successful. Additional info on this:
http://mail.python.org/pipermail/web-sig/2008-May/003439.html
http://mail.python.org/pipermail/web-sig/2008-July/003545.html

Related

Do I need to change my normal Django code when introducing Django Channels?

Hello I am a beginner in the python world, so I am still trying to understand the care when working with ASGI. I read some tutorials and documentation, as well as watched some videos on youtube. However, I was unsure on some points.
I have a small backend application using Django + Django Rest Framework.
My code is very trivial, composed of the most common concepts in the framework: views, serializers, models, urls, etc. In addition, I use a relational database.
My environment is this:
Python 3.8
Django 3
Django Rest Framework 3.11
Now, I need to add support for WebSockets and I did the basic configuration described in the Django Channels tutorial:
I installed Django Channels 2.4.0 (Daphene 2.5.0)
Added 'channels' to INSTALLED_APPS
I created a routing.py file with an empty ProtocolTypeRouter
I added ASGI_APPLICATION to my settings.py
I configured the asgi.py file to use channels
At the moment, I have not configured any channel layers
At the moment, I haven't created any WebSocket endpoint
After these configurations the runserver is using an ASGI development server and apparently my REST endpoints are all working.
Some questions:
Considering that all my code is synchronous, wouldn't it be necessary to make any adjustments to it?
This configuration above, already does all the magic necessary for my synchronous code to be executed safely in daphene considering that it is an ASGI server?
Can I serve normal HTTP and WebSockets requests using only ASGI in a reliable and stable manner? Or, is it recommended to serve HTTP traffic using WSGI and leave only WebSockets traffic to daphene?
Where exactly should care be taken regarding synchronous code?
These are my answers based on previous experiences with Django Channels 2 ...
1) Considering that all my code is synchronous, wouldn't it be necessary to make any adjustments to it?
You can safely keep your existing sync code: no adjustments are required; just make sure to call the “sync version” of django-channels API (i.e. SyncConsumer instead of AsyncConsumer).
On the other hand, Channel Layers uses a different approach, and provides only an async version.
When the call is issued from sync code, you need to use the async_to_sync wrapper; for example:
from asgiref.sync import async_to_sync
async_to_sync(channel_layer.group_send)(
group, {
"type": 'data_received',
"content": data,
})
2) This configuration above, already does all the magic necessary for my synchronous code to be executed safely in daphene considering that it is an ASGI server?
The single missing details is (in settings file):
ROOT_URLCONF = 'project.urls'
3) Can I serve normal HTTP and WebSockets requests using only ASGI in a reliable and stable manner? Or, is it recommended to serve HTTP traffic using WSGI and leave only WebSockets traffic to daphene?
With Channels 2, you can safely choose to use Daphne for both HTTP and WebSockets requests, since Daphne will auto-negotiates between HTTP and WebSocket; this is what I usually do in my projects.
Splitting HTTP and WebSocket traffic, thus:
running standard HTTP requests through a WSGI server
using Daphne (or uvicorn) only for things WSGI cannot do, like WebSockets, HTTP long-polling or other IoT protocols
is possible, but entirely optional.

Live notification/chat in django

I am making a website with django now and I want to implement a live notification feature like the one on facebook or SE.
I did some research and it seems although there's two options: ajax long polling and websockets, the latter is the way to go.
However, as you know the go to plugin for websocket 'socket.io' turns out to be a node.js plugin and the django port only seems to support python 2 and the project seems pretty much dead. I am using python 2.7 as my project interpreter but I want to future proof myself so that if I upgrade to python3 later, I don't find myself not being able to use this functionality.
So my question is this:
Is there a straight forward and future ready way to implement websocket which will be used to send live notifications and chats in django env?
Django itself is build in blocking manner, i.e. with synchronous approach. So, you cannot open persistent websocket with django app, as it will block entire django thread.
If you want to enable notification/chat within django project environment, i would recommend to use centrifuge. It is written in python, but async (non-blocking) framework is used: tornado.
But, you don't need to even know how it works, as it provides simple REST api to communicate with it.
Simplified workflow, check docs for more details:
Start centrifuge at same server, as your django project (or on another but with low latency between them)
Your front-end will open websocket with centrifuge, not with django project.
When you need to send notification, send it to centrifuge from django via REST api, and centrifuge will deliver it to needed clients!
I've already tried it and it works!
Django doesn't provide what you're looking for out of the box. You'll have to use a third party library. One that works across frameworks is Pusher.
I think you must go for Firebase it gives you awesome synchronization and any how you are going to use chat on frontend so its does not have to do anything with django environment so you can update you backend asynchron in callback with firbase. Also firebase with AngularJS provides you really really awesome three way binding.

When to use RESTful APIs in a Django project

My project
I have a backend web application written with Django and a mobile application written with HTML/CSS/jQuery and wrapped in PhoneGap. I need the mobile app to communicate with the web app and I first thought I would build my own REST API.
My understanding
WSGI is a specification (based on HTTP) that defines how to handle communications between a web server and a Python application, basically how to translate HTTP requests into Python objects and vice versa. All we need to provide to the WSGI server (gunicorn for instance) is a WSGI application. In Django we will typically have a wsgi.py file at the root of the project with
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
So Django has a built-in support for the WSGI specification and we, programmers, do not even have to think about how our application interfaces with the web server. Nice.
REST is an architecture style based on 6 constraints defining how data are transmitted between components within a program or separated programs (not necessarily web applications). A RESTful API is an API that fulfills those constraints. I heard that there is a whole framework for Django, surprisingly called django-rest-framework, that helps developers to build REST APIs.
My questions
Hey, why would I need a REST API if the WSGI application already provides a way to parse HTTP requests and return responses? I mean, since my mobile application is nothing less than an embedded webpage, why can't I just use regular urls to access my web application and return HTML code that depends on the type of device that sent the request?
If indeed a REST API is not needed in this case, what is the purpose of a REST API in a Django project? When is it useful?
Well as far as using Django Rest Framework is it has support built in to handle a lot of things like throttling, serializing and de-serializing django query sets into json and back again. It's got built in support to work with django's auth system.
As far as not using it, I suppose there is nothing wrong with having django view methods peruse posted data and serialize to and from json to send responses back, handle authentication, authorization and throttling etc...However that is a crap load of code which you will ultimately need to write for any api and not having to do that is a huge break.
Another benefit to using something like Django Rest Framework is the contribution from the community. Major companies and small companies use it alike. Typically the purpose of an API is to have external parties consume it. Something like Django Rest Framework tries to follow best practices in this regard making it easier for your customers to consume your api.

How to use Tornado work with Django? Is it a good solution?

I've a huge django project and have to use Instagram API and its subscriptions model to work. For the subscriptions, my server has to be very responsive and be ready to work asynchronously to set up a hook so as to receive notifications once the user posts. Or that's what the documentation suggests. Now will it be a good thing to use Tornado there? Just for that small part or can I do it using Django in an effective way? if so, how?
You can use the WSGI container on top of Tornado to host any WSGI application, including Django, however, when you do that the WSGI application is still running as a blocking application and will not magically be running as an asynchronous application. So, when Django is handling a request there is no ability to handle another request at the same time within Django. The solution at that point is not much different to running a single threaded WSGI server and you would need to have multiple Tornado instances to handle concurrent requests.
So all really depends on what you mean by asynchronous. You certainly can't make use of Tornado's direct asynchronous programming API in Django. Thus there isn't really any great benefit from using Tornado with Django via the WSGI interface.
As I understand you are talking about this paragraph in Instagram docs
You should build your system to accept multiple update objects per payload - though often there will be only one included. Also, you should acknowledge the POST within a 2 second timeout--if you need to do more processing of the received information, you can do so in an asynchronous task.
That's another type of "asynchronous" that Tornado provides.
I think Django + Celery will suite better for this.
Your application will work in this way:
You receive JSON-data from Instagram
Create a celery-task, e.g. instagram_process.delay(request.raw_post_data) or instagram_process.delay(request.body) according to your Django version
Response to Instagram with 200 status code
In instagram_process task you do all your procession - parse JSON, store it do database and anything else you need.
If you want to check X-Hub-Signature you can either do it between steps 1 and 2, or pass this header to the task and verify the signature at step 4.
You can use tornado.wsgi to integrate Tornado with other WSGI compliant frameworks. Check out this demo project for details:
https://github.com/bdarnell/django-tornado-demo

Adding django-socketio to existing Apache/mod_wsgi/Django site

Can anyone provide or link to a tutorial for adding django-socketio functionality to an existing Django site that uses Apache and mod_wsgi?
Can they work in parallel or does the runserver_socketio command need to handle all requests?
This Question is related but offers little practical information.
Thanks
You should be able to run the regular site behind a public facing server like Apache, with the runserver_socketio part just serving websockets on a separate port. As described in the question you linked to, you'll need to work out if it's possible to proxy websockets through your web server if that's a requirement for you, but as also mentioned the gevent server used by runserver_socketio is more than capable.
When running separate instances like this, the "out of band" functions won't work, as they depend on shared state:
django_socketio.broadcast(message)
django_socketio.broadcast_channel(message, channel)
django_socketio.send(session_id, message)
You'll also need to add the SOCKETIO_PORT to the regular Django project's settings so that it knows which port to use.