Theju's tryst with life

Confista: A conference management app

I can't believe I had been living under a rock all this while! How could I have missed Pinax? I knew it existed but was under a wrong impression that it was only for the social stuff.

Recently, I forced myself to look at Pinax for a project and after evaluating it, I must admit that I was blown off my feet. It is really awesome! If django is a "web framework for perfectionists with deadlines" then Pinax is "the fastest way to develop awesome django apps without repeating and embarassing yourself".

Coming to the point of this post, I have managed to port the fossconf app that powered Pycon India 2009 to Pinax. Actually, I have not ported all the features but the current version is fairly usable. I would love to hear feedback from you regarding the app that I named Confista (Conference + Assistant). I know the name sucks but could not think of something better! If you wish to contribute to the project, please fork the code and suggest improvements.

And there is another Pinax based project underway to power the Avayam Trust site that I am associated with as a web master.

RFC: Comments framework usage documentation

This is my attempt at ticket #9819 which aims for better documentation to the comments framework. This is my second attempt at writing documentation and I have uploaded a patch to the ticket but wanted some feedback here without spamming the timeline.

Example of using the in-built comments app

  1. Follow the first three steps of the quick start guide in the documentation.
  2. Now suppose, you have an app (blog) with a model (Post) to which you want to attach comments. Let us also suppose that you have a template called blog_detail.html where you want to display the comments list and comment form.
  3. First, we should load the comment template tags in the blog_detail.html so that we can use it's functionality. So just like all other custom template tag libraries:
{% load comments %}
  1. Next, let us add the number of comments attached to the particular model instance of Post. For this we assume that a context variable object_pk is present which gives the id of the instance of Post.

    The usage of the get_comment_count tag is like below:

{% get_comment_count for blog.post object_pk as comment_count %}
<p>{{ comment_count }} comments have been posted.</p>

If you have the instance (say entry) of the model (Post) available in the context, then you can refer to it directly:

{% get_comment_count for entry as comment_count %}
<p>{{ comment_count }} comments have been posted.</p>
  1. To get a list of comments, we make use of the get_comment_list tag. This tag's usage is very similar to the get_comment_count tag. We need to remember that the get_comment_list returns a list of comments and hence we will have to iterate through them to display them:

    {% get_comment_list for blog.post object_pk as comment_list %}
    {% for comment in comment_list %}
    <p>Posted by: {{ comment.user_name }} on {{ comment.submit_date }}</p>
    ...
    <p>Comment: {{ comment.comment }}</p>
    ...
    {% endfor %}
    
  2. Finally, we display the comment form, enabling users to enter their comments. There are two ways of doing so. The first is when you want to display the comments template available under your comments/form.html. The other method gives you a chance to customize the form.

    The first method makes use of the render_comment_form tag. It's usage too is similar to the other two tags we have discussed above:

{% render_comment_form for entry %}

It looks for the form.html under the following directories (for our example):

comments/blog/post/form.html
comments/blog/form.html
comments/form.html
Since we customize the form in the second method, we make use of another tag called get_comment_target. This tag on rendering gives the URL where the comment form is posted. Without any customization, get_comment_target
evaluates to /comments/post/. We use this tag in the form's action attribute. The get_comment_form tag renders a form for a model instance by creating a context variable. One can iterate over the form object to get individual fields. This gives you fine-grain control over the form:
{% for field in form %}
{% ifequal field.name "comment" %}
  <!-- Customize the "comment" field, say, make CSS changes -->
...
{% endfor %}

But let's look at a simple example:

{% get_comment_form for entry as form %}
<!-- A context variable called form is created with the necessary hidden fields,
timestamps and security hashes -->
<table>
<form action="{% comment_form_target %}" method="POST">
  {{ form }}
  <tr>
    <td></td>
    <td><input type="submit" name="preview" class="submit-post" value="Preview"></td>
  </tr>
</form>
</table>
  1. If you want your users to be able to flag comments (say for profanity), you can just direct them (by placing a link in your comment list) to /flag/{{ comment.id }}/. Similarly, a user with requisite permissions ("Can moderate comments") can approve and delete comments. This can also be done through the admin as you'll see later. You might also want to customize the following templates:

    • flag.html
    • flagged.html
    • approve.html
    • approved.html
    • delete.html
    • deleted.html

    found under the directory structure we saw for form.html.

  2. Suppose you want to export a feed of the latest comments, you can use the in-built LatestCommentFeed. Just enable it in your project's urls.py:

from django.conf.urls.defaults import *
from django.contrib.comments.feeds import LatestCommentFeed

feeds = {
    'latest': LatestCommentFeed,
}

urlpatterns = patterns('',
# ...
  (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
     {'feed_dict': feeds}),
# ...
)

Now you should have the latest comment feeds being served off /feeds/latest/.

  1. Now that we have the comments framework working, we might want to have some moderation setup to administer the comments. The comments framework comes in-built with generic comment moderation. The comment moderation has the following features (all of which or only certain can be enabled):

    • Enable comments for a particular model instance.
    • Close comments after a particular (user-defined) number of days.
    • Email new comments to the site-staff.
  2. To enable comment moderation, we subclass the CommentModerator and register it with the moderation features we want. Let us suppose we want to close comments after 7 days of posting and also send out an email to the site staff. In blog/models.py, we register a comment moderator in the following way:

from django.contrib.comments.moderation import CommentModerator, moderator
from django.db import models

class Post(models.Model):
    title   = models.CharField(max_length = 255)
    content = models.TextField()
    posted_date = models.DateTimeField()

class PostModerator(CommentModerator):
    email_notification = True
    auto_close_field   = 'posted_date'
    # Close the comments after 7 days.
    close_after        = 7

moderator.register(Post, PostModerator)
  1. The generic comment moderation also has the facility to remove comments. These comments can then be moderated by any user who has access to the admin site and the Can moderate comments permission (can be set under the Users page in the admin).

  2. The moderator can Flag, Approve or Remove comments using the Action drop-down in the admin under the Comments page.

    Note

    Only a super-user will be able to delete comments from the database. Remove Comments only sets the is_public attribute to False.

A wiki with a couchdb backend and django

Recently, I had a requirement for a personal simple wiki. I checked out various options like TiddlyWiki, MoinMoin and MediaWiki but wanted something very simple and something that didn't use a database server or flat files and was portable (and hostable). So I quickly wrote up a wiki that used couchdb as its backend and django for the web app.

Couchdb stores the revisions of the edits and so I could always revert to a previous version if required. It also saved me the need of installing an RDBMS.

I released the code for the app at github. It's quite rudimentary at the stage but should be good enough for personal use. Hopefully, with a little more time and effort, I should be able to achieve what I set out for. (Check a demo). Just create a page of your choice by directing your browser to it.

Note: User registration is blocked at the moment. But feel free to edit and create pages anonymously.

Interested in trying out the code on your machine?

INSTALL

  • Fetch the auth and sessions backends for couchdb from here and add them to the INSTALLED_APPS in your project's settings.py as per the instructions. Also requires couchdb-python.
  • Place the wiki app and reference it too in the INSTALLED_APPS.
  • Append the wiki/templates directory (with the absolute path) in the TEMPLATE_DIRS attribute of the settings.py.
  • Add a pointer to the wiki URL and account urls in your urls.py like
(r'^wiki/', include('wiki.urls'))
(r'^accounts/', include('django.contrib.auth.urls'))
  • Add the following attributes to your settings.py.

    COUCHDB_HOST = 'http://path_to_couchdb_server:port_num/'
    # If you don't want unauthenticated users to create
    # pages, then set the below attribute to False
    ALLOW_UNAUTH_PAGE_CREATION = True
    # The below attribute is optional, if not specified
    # it redirects to an empty page.
    WELCOME_PAGE = '/path/to/default/star/up/page/'
    
  • Your wiki is ready!

Please let me know how you feel about this app.

Reusable App: Authenticated Comments

This app had been on my todo list for a long time. Today, no matter how much I tried to procrastinate, I could not ignore it and hence decided to scratch my itch and get it done. I swore I wouldn't even get up for a glass of water until it was done. Luckily, this took lesser time than I anticipated and I was spared of breaking my resolve!

There are certain sites that require only authenticated users to post comments, this app specifically targets such cases.

It builds on my previous posts sans the javascript hack. To make the code very condense and easy to use, it uses "Two-phased template rendering" that I saw in Ella via Adrian Holovaty's post. From a security point, it auto-escapes django template code injected in through the comments in the middleware.

How to use it

  • Fetch the source from here and copy the auth_comments app over to your project and reference it under the INSTALLED_APPS in settings.py
  • Add the COMMENTS_APP attribute in settings.py and set the value to auth_comments
  • Make sure that you have the following TEMPLATE_CONTEXT_PROCESSORS activated in your settings.py.
TEMPLATE_CONTEXT_PROCESSORS=(
  "django.core.context_processors.auth",
  "django.core.context_processors.request",
  "django.core.context_processors.media"
 )
  • Append the auth_comments/templates directory in the TEMPLATE_DIRS attribute of settings.py
  • Activate the comment urls in your project's urls.py
(r'^comment/', include('django.contrib.comments.urls')),
  • In your templates, when you want to render the authenticated comment form, just use the following code.
{% load auth_comments %}
...
{% render_auth_comment_form for app.model object_pk %}

This code is equivalent to

{% if request.user.is_authenticated %}
  {% render_comment_form for app.model object_pk %}
{% else %}
  Some standard message to be shown if user not logged in.
{% endif %}

The standard message is picked up from the DEFAULT_UNAUTH_COMMENT_MESSAGE attribute of settings.py which you can set to override the default message.

If you liked the app, do let me know. Also please fork and improve the code if you wish to improve it.

Yet another redesign at thejaswi.info

Oh yes!!! You are seeing it right! There's been another redesign of my site.

Technology fascinates me and I cannot get enough of it. This time I wanted my blog powered by the latest and coolest technology. Want to know more?

CouchDB powers the heart of the blogging engine as opposed to an RDBMS. CouchDB-python talks to the DB and the web app. How on earth could I have left my favourite framework out of this cool stuff! I make use of the Django templates and views for the presentation and logic.

CouchDB stores the posts, comments, authentication related data and session data. I have written custom auth and session backends in Django that store the data on the DB. The source has been released and is available here.

The advantages of using couchDB:

  • It scales tremendously. Suppose my blog readership touches a few million, all I would need to do is to add more couchDB nodes and voila it scales!!!
  • Since couchDB uses HTTP as the underlying protocol, it can be cached very easily using standard cache utilities like Squid and Varnish.
  • It is schema-less. I could easily add/edit and remove fields from the DB without having to get frightened about it's integrity.

The disadvantages of using couchDB:

  • couchDB is growing fast and still does not have a few features (slated to be released soon) and the API is a moving target.
  • It can give you a few scares from time to time. I almost lost my data when I made a few cfg changes. After googling around, I figured out that the data was safe but couchDB would require a reinstall.

Hope this time, the technology powering my blog is not obsoleted so fast ;-).

PS1: If you have come to the site from a previous bookmark, please update your bookmarks. I am sorry about breaking your results.

PS2: Some services on my blog are still missing, I promise to have them up at the earliest.

PS3: I am in the process of releasing the source code of the site. If you are one of the impatient folks, please ping me.

The number of posts are 23. The number of pages are 5. Next