Comments app in Django

I wonder how ``is_public`` supposed to be used in FreeComments? Neither get_comment_count nor get_comment_list seems aware of it.

Recently i set up comment_utils app, which can use akismet module and some other ways to decide if comment shouldn't be public. Akismet check works very good, and spam comments get ``is_public`` flag set to false. However, comments template tags get_comment_count and get_comment_list don't use it. And display/count comments no matter if they're public or not.

As of now, i do the following:

{% get_free_comment_list for blog.entry object.id as comment_list %}
    {% for comment in comment_list %}
        {%if comment.is_public %}
        [...]
        {% endif %}
    {% endfor %}

get_free_comment_count still returns the number of all comments though.

Some things have broken in django/flup

After adding autoescape stuff to Django svn, at least several things have broken it seems.

Firstly i noticed the problem with ``flat pages``. Instead of seeing my static data, i got ``Unhadled exeption`` in reply. In logs i found following:

2007-12-01 17:39:13: (mod_fastcgi.c.2588) FastCGI-stderr: Traceback (most recent call last):
  File "/usr/lib/python2.5/site-packages/flup/server/fcgi_base.py", line 558, in run
    protocolStatus, appStatus = self.server.handler(self)
  File "/usr/lib/python2.5/site-packages/flup/server/fcgi_base.py", line 1120, in handler
    write(data)
  File "/usr/lib/python2.5/site-packages/flup/server/fcgi_base.py", line 1062, in write
    assert type(data) is str, 'write() argument must be string'
AssertionError: write() argument must be string

As seen above, error reported by Flup, which is used by Django to run as fastcgi server. Type of data passed to line 1062 is django.utils.safestring.SafeString now and AssertionError is raised.

There's a ticket already created because of this issue, and even reported to flup's author. But there's no solution to the problem as of now.

Setup of libpam-mysql, libnss-mysql-bg with Django admin application

When you have many servers to manage, it can be usefull to have some centrelized server for user authentication and accounting. Libpam-mysql and libnss-mysql-bg permit keep your data in mysql db and make it possible to use it by pam-aware services on your system.

From the other hand, it is goot to have some web interface to manage all these records. I decided to use excellent Admin application from Django framework for this purpose

Here are the simple steps:

$ django-admin startproject webadmin
$ cd webadmin
$ ./manage.py startapp pam

After this, costumize your settings.py and add similar models.py to the pam/ folder.

To prevent system and mysql uids/gids overlapping, it's probably a good idea to set Mysql sequence numbers to some reasonable value, like 2000 or similar.

# apt-get install libnss-mysql-bg libpap-mysql After this, make you config files look similar to this:

# /etc/libnss-mysql.cfg
getpwnam    SELECT username,'x',uid,gid,gecos,homedir,shell \
            FROM pam_user \
            WHERE username='%1$s' AND is_active=1 \
            LIMIT 1
getpwuid    SELECT username,'x',uid,gid,gecos,homedir,shell \
            FROM pam_user \
            WHERE uid='%1$u' \
            LIMIT 1
getspnam    SELECT username,password,lstchg,min,max,warn,inact,expire,flag \
            FROM pam_user \
            WHERE username='%1$s' \
            LIMIT 1
getpwent    SELECT username,'x',uid,gid,gecos,homedir,shell \
            FROM pam_user
getspent    SELECT username,password,lstchg,min,max,warn,inact,expire,flag \
            FROM pam_user
getgrnam    SELECT name,password,gid \
            FROM pam_group \
            WHERE name='%1$s' \
            LIMIT 1
getgrgid    SELECT name,password,gid \
            FROM pam_group \
            WHERE gid='%1$u' \
            LIMIT 1
getgrent    SELECT name,password,gid \
            FROM pam_group
memsbygid   SELECT pam_user.username \
            FROM pam_user,pam_user_groups \
            WHERE pam_user_groups.group_id='%1$u' AND pam_user.uid=pam_user_groups.user_id
gidsbymem   SELECT pam_user_groups.group_id \
            FROM pam_user,pam_user_groups \
            WHERE pam_user.username='%1$s' AND pam_user.uid=pam_user_groups.user_id

host        192.168.1.1
database    webadmin
username   webadmin
password    secret
timeout      3
compress    0
# /etc/libnss-mysql-root.cfg
username    nss-root
password    s3cr3t

After this, you need to add some data into db using Django admin interface, and tweak pam configuration. In Debian/Ubuntu this can be done like this:

# /etc/nsswitch.conf
passwd:         compat mysql
group:          compat mysql
shadow:         compat mysql

[...]
# /etc/pam.d/common-auth

auth    [success=1 default=ignore]      pam_unix.so
auth    required                        pam_mysql.so user=webadmin passwd=secret host=192.168.1.1 db=webadmin table=pam_user usercolumn=pam_user.username passwdcolumn=pam_user.password crypt=1 [where=pam_user.is_active="1"]
auth    required                        pam_permit.so
# /etc/pam.d/common-account

account [success=1 default=ignore]      pam_unix.so
account required                        pam_mysql.so user=webadmin passwd=secret host=192.168.1.1 db=webadmin table=pam_user usercolumn=pam_user.username passwdcolumn=pam_user.password crypt=1 [where=pam_user.is_active="1"]
account required                        pam_permit.so
# /etc/pam.d/common-password

password       sufficient      pam_mysql.so user=webadmin passwd=secret host=192.168.1.1 db=webadmin table=pam_user usercolumn=pam_user.username passwdcolumn=pam_user.password crypt=1 [where=pam_user.is_active="1"]
password       required        pam_unix.so nullok obscure min=4 max=8 md5 try_first_pass
# /etc/pam.d/common-session

session required    pam_mkhomedir.so skel=/etc/skel/ umask=0022
session required        pam_unix.so

That's all! Now things like id <some_mysql_user> should work.

P.S.
I had to do /etc/init.d/sshd reload to make it work for new mysql users.

Django book pre-release

Today two first chapters of the Django Book are available online. There is a cool ajax based (YUI) comment system available for comments/corrections/etc. The book is available under the GNU Free Documentation License, which means it's free to read and redistribute. Next chapters are coming..seems two new chapters "The basics of generating Web pages" and "The Django template system" will be available on November 6, 2006. Updates are also available via Atom feed

Pinging Ping-O-Matic from Django blog

As soon as your blog content updates, you may want to ping some services like Technorati. Django already has module django.contrib.sitemaps, which can ping google along with sitemap generation. But what if you want to update other search engines too? There's a plenty of services, which support RPC, so it is possible to ping them once your blog got updated. Or you can use a wonderful service Ping-O-Matic, which will do the work for you.

Ping-O-Matic is a service to update different search engines that your blog has updated. You can let it know about your updates using ordinary GET request, or using RPC call. This RPC call is just an HTTP request with some details in xml format. Python has a great XML-RPC client library xmlrpclib which makes work with RPC simple and pleasant.

Here's the simple code, which you can save in your app directory:

That's all! Now all you need to do is to call it once your blog gets updated. This can be done by subclassing save() method of your model:

Entry is the name of my model in the Blog application.

Django powered blog launched!

After a long period of time while my domain fxp0.org.ua was unused, i finally made a small blog application with Django and put it on the web. Actually, i've been playing with Django since January, but i have not written anything, that i could utilize on the web. So here's my first micro app :) Though it's hardly can be called an application :) Django made development so easy and pleasant! Entire blog application can be written in a few simple steps! Due to the fact that i'm sysadmin, i spent much more time playing with all that html/css stuff :) And this partially explains the weird look of my site :)