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:
The disadvantages of using couchDB:
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.
This is the final part in the "I blog in ReSt" series. This part discusses about how to get the templates going for the blog.
{% load custom_filters %}
{% load comments %}
{% load markup %}
{% load tagging_tags %}
{% block title %}Title of the Blog{% endblock %}
{% block content %}
{% for blog in blog_object_list %}
{{ blog.blog_title }}
{{ blog.blog_file|open_file|restructuredtext }}
Published on {{ blog.blog_date_pub|date:"F j, Y" }}
{% get_free_comment_list for blog_app.blog_model blog.id as comment_list %}
{% get_free_comment_count for blog_app.blog_model blog.id as comment_count %}
{% if comment_count %}
{% for comment in comment_list %}
<div class="comment_{% cycle odd,even %}" id="c{{ comment.id }}">
<span class="comnum"><a id="c{{ comment.id }}"
href="#c{{ comment.id }}">#{{ forloop.counter }}</a></span>
<p><strong>{{ comment.person_name|escape }}</strong> commented,
on {{ comment.submit_date|date:"F j, Y" }} at {{ comment.submit_date|date:"P" }}:</p>
{{ comment.comment|restructuredtext }}
</div>
{% endfor %}
{% endif %}
<p>Post a comment</p>
{% free_comment_form for blog_app.blog_model blog.id %}
{% endfor %}
Viewing page <strong>{{ page }} / {{ pages }}</strong>. Total number of posts are {{ hits }}.
{% if has_previous %}
{% if year %}
{% if month %}
<p><a href="/blog/{{ year }}/{{ month }}/page/{{ previous }}/">Newer Posts</a></p>
{% else %}
<p><a href="/blog/{{ year }}/page/{{ previous }}/">Newer Posts</a></p>
{% endif %}
{% else %}
{% if tag %}
<p><a href="/blog/tag/{{ tag }}/page/{{ previous }}/">Newer Posts</a></p>
{% else %}
<p><a href="/blog/page/{{ previous }}/">Newer Posts</a></p>
{% endif %}
{% endif %}
{% endif %}
{% if has_next %}
{% if year %}
{% if month %}
<p><a href="/blog/{{ year }}/{{ month }}/page/{{ next }}/">Older Posts</a></p>
{% else %}
<p><a href="/blog/{{ year }}/page/{{ next }}/">Older Posts</a></p>
{% endif %}
{% else %}
{% if tag %}
<p><a href="/blog/tag/{{ tag }}/page/{{ next }}/">Older Posts</a></p>
{% else %}
<p><a href="/blog/page/{{ next }}/">Older Posts</a></p>
{% endif %}
{% endif %}
{% endif %}
{% endblock %}
You might be wondering what {% load custom_filters %} is. As the name suggests it is a custom filter to read the contents of the file and return them to the restructuredtext filter.
from django import template
register = template.Library()
def open_file(value):
"Opens the contents of the file given in value."
try:
f = open(value,"r")
contents = f.read()
except IOError:
return None
f.close()
return contents
# Register the Filter
register.filter(open_file)
The restructuredtext is a filter from django.contrib.markup. The django.contrib.markup currently supports three markup languages Textile, Markdown and ReSt.
Django has an in-built comment system that can be activated almost instantly. For activating comments add the django.contrib.comments to your INSTALLED_APPS in settings.py. There are two types of Comments Systems:
The best part about Django's Comment System is that it is extremely easy to use but its biggest drawback is that it hasn't been documented yet. This is no lame excuse for not using Django Comments. In fact lots of users have blogged on how to use the Comment System. Feel free to search and you'll get hold of them. The one link that explains the comment system in detail would be this.
The rest of the code is regarding pagination. Refer here for more details regarding it.
Now you have a blog written in Django that has all the basic features that Blogger has. Also the blog is highly extensible. Extend the blog and let me know of some cool features that you built into your blog.
Once done with setting up the project, we need to code our views and templates to complete the blog. This part deals with coding the views for the blog. The different views that we require are
So let's edit the urls.py file in the project directory to reflect on the urlpatterns.
('^blog/$', get_blog_first_page),
('^blog/(?P<year>\d{4})/$', get_posts_by_year),
('^blog/(?P<year>\d{4})/page/(?P<page>\d)/$', get_blog_page_by_year),
('^blog/(?P<year>\d{4})/(?P<month>\d{2})/$', get_posts_by_month),
('^blog/(?P<year>\d{4})/(?P<month>\d{2})/page/(?P<page>\d)/$', get_blog_page_by_month),
('^blog/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', get_posts_by_day),
('^blog/tag/(?P<tag>[^/]+(?u))/$',tagged_object_list,dict(model=Blog_Model, paginate_by=1, \
allow_empty=True,template_object_name='blog_object', template_name='blog.html',\
extra_context={"tag":1,})),
('^blog/tag/(?P<tag>[^/]+(?u))/page/(?P<page>[0-9]+)/$',tagged_object_list,dict(model=Blog_Meta, \
paginate_by=1, allow_empty=True, template_object_name='blog_object', template_name='blog.html',)),
By doing so we will be accepting all urls like
/blog/ # the first page with latest items
/blog/2007/ # the first page of all blog posts from 2007
/blog/2007/page/4/ # the fourth page of blog posts from 2007
/blog/2007/10/ # blog posts from October 2007
/blog/2007/09/page/2/ # the second page from November 2007
/blog/2007/11/15/ # the post on 15 November 2007
/blog/tag/django/ # Posts with tag django
/blog/tag/django/page/7/ # Seventh page with tag django
Django provides a date-based generic view that saves us from the writing views for date filtering etc. But date-based generic views do not provide pagination by default. But django is powerful and highly extensible. It provides an Object Paginator which can be used for paginations. So I will use a list-based generic view to mimic the date-based generic views with pagination. Open the views.py file in blog_app and paste the following code.
from django.core.paginator import ObjectPaginator
from blog_app.models import Blog_Model
from django.http import HttpResponse, Http404
from django.template import loader, Context
from django.views.generic.date_based import archive_day
from django.views.generic.list_detail import object_list
import tagging
# Number of Entries per page (paginate_by)
num_entries_per_page = 7
def get_blog_page(request,page):
queryset = Blog_Model.objects.order_by("-blog_date_pub")
paginator = ObjectPaginator(queryset, num_entries_per_page)
cloud_list = tagging.models.Tag.objects.cloud_for_model(Blog_Model,steps=2)
paginator.pages
if int(page) in paginator.page_range:
return object_list(request,queryset,num_entries_per_page,page,template_name='blog.html',\
template_object_name='blog_object',extra_context={'cloud_list': cloud_list,})
else:
raise Http404
def get_blog_first_page(request):
return get_blog_page(request,1)
def get_blog_page_by_year(request,year,page):
queryset = Blog_Model.objects.filter(**{"blog_date_pub__year":year}).order_by("-blog_date_pub")
try:
assert queryset
except AssertionError:
raise Http404
paginator = ObjectPaginator(queryset, num_entries_per_page)
paginator.pages
cloud_list = tagging.models.Tag.objects.cloud_for_model(Blog_Model,steps=2)
if int(page) in paginator.page_range:
return object_list(request,queryset,num_entries_per_page,page,template_name='blog.html',\
template_object_name='blog_object',extra_context={"year":year,'cloud_list': cloud_list,})
else:
raise Http404
def get_posts_by_year(request, year):
return get_blog_page_by_year(request,year,1)
def get_posts_by_day(request,year,month,day):
month_dict = {1:"Jan",2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",\
9:"Sep",10:"Oct",11:"Nov",12:"Dec"}
try:
month_name = month_dict[int(month)]
except ValueError:
raise Http404
cloud_list = tagging.models.Tag.objects.cloud_for_model(Blog_Model,steps=2)
return archive_day(request,year,month_name,day,Blog_Model.objects.all(),'blog_date_pub',\
template_name='blog.html',template_object_name='blog_object',\
extra_context={'cloud_list': cloud_list,})
I have not given the complete view. You can check it out here. The next part in this series talks about templates.
Nowadays everyone blogs. Blogs have become the medium for people to express almost everything. So I started blogging in January on Blogger. Initially I was satisfied with it but started feeling cramped for features. Wordpress and PyBlosxom looked like good alternatives but it was the latter that impressed me the most. I wanted to blog using PyBlosxom. Then I realized, what's the point in knowing Django and still not writing your own blog app.
My requirements for the blog were:
File-System based: Storing all the contents of the blog in a database didn't appeal to me especially when you are restricted by 40 Megs of RAM by your hosting provider (I am not complaining, that's all that I can afford).
Once done with the requirements, I started scripting for my blog and here is a step-by-step process of how to go about it. The blog can be built for any markup langauge like Markdown, PyTextile or ReSt.
$ django-admin.py startproject myproject
$ python manage.py startapp blog_app
from django.db import models
from tagging.models import Tag
from tagging.fields import TagField
class Blog_Model(models.Model):
blog_title = models.CharField(max_length=250)
blog_date_pub = models.DateField()
blog_file_name = models.CharField(max_length=250)
blog_tags = TagField(max_length=255)
def save(self):
# Override the save method of Model.
super(Blog_Meta, self).save()
self.tags = self.blog_tags
def _get_tags(self):
return Tag.objects.get_for_object(self)
def _set_tags(self, blog_tags):
Tag.objects.update_tags(self, blog_tags)
tags = property(_get_tags, _set_tags)
def __unicode__(self):
return self.blog_title
$ python manage.py syncdb
$ python manage.py runserver
In the next part we see how to write the views and templates for the blog.