A django app providing reverse-ajax chat rooms
Chatrooms is an app that provides multi-user chat rooms for your django site.
It’s completely based on jQuery and gevent, whose libraries have been used to implement long polling.
It provides a set of models, views and templates ready out of the box and easily customizable.
Install the egg from pypi:
$ pip install django-chatrooms
or get the latest revision from github:
$ pip install -e git+git://github.com/qubird/django-chatrooms#egg=chatrooms
If you use buildout, just add django-chatrooms to your eggs part.
Once the egg is installed, add the following apps to your settings.INSTALLED_APPS:
INSTALLED_APPS = ( # ..., 'polymorphic', 'chatrooms', # ..., )
Then include chatrooms urls to your urlpatterns:
urlpatterns = patterns('', # ..., url(r'^chat/', include('chatrooms.urls')), # ..., )
Make sure you also added staticfiles_urlpatterns to urlconf like:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns urlpatterns += staticfiles_urlpatterns()
and 'django.contrib.staticfiles' is amongst INSTALLED_APPS.
Then you’re ready to run syncdb.
To use the app with servers that pre-fork the application before running, like gunicorn does, you need to use some sort of interprocess communication.
chatrooms.utils.redis_handlers module contains the RedisMessageHandler class, which can be set as settings.CHATROOMS_MESSAGE_HANDLERS to use the application in a gunicorn-like environment. The module needs a redis instance installed and running to work.
Also a chatrooms.utils.celery_handlers.CeleryMessageHandler class has been included. It can be used as settings.CHATROOMS_MESSAGE_HANDLERS as well, but needs celery to be installed.
See the Message Handlers section to know how to implement your own handlers.
Using the app
The app installs two models: Room and Message. Rooms can be created by Admin Site. Room objects have the following fields:
|slug:||which identifies the room in urls and views|
|subscribers:||which references a set of users (not used by default)|
|which tells whether the room is accessible only to logged users, or event to “guests”. A guest user is asked to choose a guest name before entering the room.|
|password:||These fields aren’t used by default. They might be useful for implementing custom policies of access. See the Custom access policies section for further details.|
Besides the core views that handle ajax requests to make the chat work, some class-based views have been designed.
These are in views.py:
- RoomsListView, which shows the list of rooms filtering the ones requiring a logged user if the user is not authenticated
- RoomView, which renders the actual room page
- GuestNameView, which is shown to non-logged users entering an allow_anonymous_access room to choose a guest name
The templates you might want to override are
chatrooms/guestname_form.html, which is rendered by GuestNameView: it shows the form for choosing a guest name
chatrooms/rooms_list.html, which is rendered by RoomsListView
chatrooms/room.html, which is the skeleton of the page where chat objects are placed dynamically. The page includes the js/room.js script which requires a getContext() function like:
Some elements are required by room.js and need to be included in room.html:
static/css folder contains the file room.css you might want to override to re-style the room page.
The test_gevent command has been implemented to test the chat features that use gevent libraries.
utils.handlers.MessageHandler class implements the methods
handle_received_message(sender, room_id, username, message, date, [user])
sender: the ChatView instance room_id: the id of the room where the message was sent username: username or guest name of the user who sent the message message: the content of the sent message date: the timestamp of the sent message user: request.user if user is authenticated, else None
retrieve_messages(chatobj, room_id, latest_msg_id)
chatobj: the ChatView instance room_id: the id of the room whose messages are requested latest_msg_id: the id of the latest message sent to the room
chatobj: the ChatView instance room_id: the id of the room whose latest message id is requested
handle_received_message method is designed to perform operations with the received message such that retrieve_messages is able to retrieve it afterwards.
retrieve_messages must return a list of tuples like [(message_id, message_obj), ...], where message_obj is an instance of Message or an object with at least the following attributes:
and message_id is a unique progressive identifier.
get_latest_message_id must give back the id of the latest message received, consistently to the ways messages are stored and retrieved.
To implement your handlers you need to create a class extending chatrooms.utils.handlers.MessageHandler, say my.app.MyHandlerClass, override the aforementioned methods, and add to your settings:
CHATROOMS_HANDLERS_CLASS = 'my.app.MyHandlerClass'
This way your defined methods will be used as default handlers for received messages and requests for messages.
See utils.handlers.MessageHandler and ajax.chat.ChatView docstrings for further details on these classes.
Custom access policies
Access to rooms can be controlled defining a function which takes request and user as arguments, and returns True or False whether the user is allowed to access the room or not (room_id is given as a GET parameter of the request).
Once you defined your function, say my.app.user_can_enter_foo, add to your settings:
CHATROOMS_TEST_USER_FUNCTION = 'my.app.user_can_enter_foo'
Your function will be used as a test by view decorators. When the user sends ajax requests to send or get chat messages, or get the connected users list, request and user are passed to your function. If it returns False, a 403 Forbidden Resource response is given, else the request is normally processed.
Denis Bilenko ‘s webchat example has been a great starting point for the design of this app.
- Users list methods could be improved to work properly in multi-process environments, as it’s been done with message handlers.