Archive for April, 2008
Wayanad
Kerala is a popular tourist destination in south India. With pleasant climate and equally pleasant people, it is rightly named as ‘god’s own country’.
Wayanad is one such popular destination on the north-east of the state. Being part of Western Ghats, it boasts of excellent natural beauty – wild life sanctuaries, mountain ranges, islands and lakes.
Three days are not sufficient enough to enjoy all of Wayanad; but unfortunately that was all the time that we had. We planned to utilize the best of these three days – we had detailed plans of what to see on each day.
We started at about 6 am. from Bangalore in Toyota Qualis. We traveled via Mandya and reached Rain Country Resorts at about 1 pm., ready for lunch. It was an indicator of what we were going to have in the coming days – it was an excellent lunch.
After lunch, we left to Pookot Lake. We took a boat ride and then strolled along the lake for sometime.
Later in the day, at the resort, we were informed that a bandh was organized the next day to protest against the recent fuel hike. We didn’t like it; but what is a travel plan, if it doesn’t change during its course?
Though all of us took a book with us, I didn’t want to spend a whole day sitting in the resort. I discussed with the resort staff for options. One of them offered to be a guide to walk us through the woods to the near-by peak. My brother-in-law and I gladly agreed.
I was excited at change of plan. Walking through woods was not in our initial plan. We had planned to hop from one tourist spot to the other. But this sudden change will give us an opportunity to spend much more time with the nature.
I was excited for another reason too – I was reading Bill Bryson’s adventurous walk through the Appalachian Trail’ in his book ‘A Walk in the woods‘. Obviously I was thrilled to take a walk through the woods; of course my brother-in-law is no match for Katz (Bryson’s partner in the walk), but he is closer.
We left after breakfast. The initial climb was a steep one and tiring. While BIL (brother-in-law) and I were panting and falling behind (much like Katz), the guide went on walking as if it was anything normal. I was afraid that our hike will end much before it started! But we survived.
The woods were wild and unspoiled. It was a fantastic feeling to be in the woods listening to the birds chirp and to the rustling sound of dry leaves on the ground. The rest of the walk was not so much steep as the initial one and we were glad about it.
The guide warned us that there were leeches along the route and he took a bottle of salt water in case it was needed. We didn’t use it though.
The final piece was a steep climb on the hill. While the guide climbed up without much effort, it took us a lot of sweat. But when we stood on top of the hill, we felt such an elation – not just because we made it to the top of the hill, but the scenery was splendid. We were on a hill surrounded on all directions by mountains with layers of natural beauty. Having done a basic degree in geology, BIL went about giving me information of the rocks that were surrounding us. Though it was mid noon with sun scorching, we stayed back as long as we could.
We did have a concern that we will be bored for the rest of the day. But we were wrong. As my sister was flying frequently and all of us were caught up in the pace of our work, we didn’t have any family time for few months. So this gave us a chance to sit down as a family and talk. We talked – talked about our childhood; dad’s and mom’s childhood days; our growing up; how life has changed and all else. We didn’t realize how fast time went by until one of the staff came in to call us for dinner. We resumed the family chit-chat after dinner too. All of us felt pretty good about the day.
Next day we left to Tholpatty wild life sanctuary. We were the first ones to take the safari and we expected a thrilling one; but we didn’t see any animals on the way. It was a disappointing one.
Immediately after breakfast, we went to Kuruva island, an uninhibited group of small islands. We were in the absolute tranquil with the nature. Having developed a liking for un-spoilt nature, I was enjoying each moment of the walk through the tall trees.
Kuruva island is not just a long stretch of tall trees; but it is made up of many rivulets, if I remember there are around 64 of them. Crossing each of them was dangerous – we had to cross on rocky bed as the stream flows through them. In some places water was knee deep. We were debating if we need to return without taking a risk on these rivulets, as my mom and dad were with us. But my mother surprised us saying, let us do it boys! We carefully crossed about 9 rivulets; in each my mother surprising us with her strength and stamina.
Every good thing comes to an end and so was this trip. But the trek through the woods, Crossing of rivulets with my parents and the quality time we had with each other will make us to remember our trip to Wayanad stay in our mind for a long time to come.
Enjoy some of the photos here. More photos in Flickr.
Group of bikers followed us.
In Pookot Lake
Cute, isn’t it?
Natural Swimming Pool in the Resort
Shot during the Camp-fire in the Resort
Deer skull found on our trek
Wild Mushroom. There were many more wild flowers
From the top of the hill
title="on the way down" href="http://www.flickr.com/photos/22003141@N00/2278854855/" target="_blank">
BIL and the guide walking down from the hill
Jeep is an economical vehicle owing to the hilly surroundings
A simple ‘Twitter’ clone in Django
It started when my boss challenged me to write a twitter/orkut for our department. Having already decided to learn web development with Django (read about it here), I jumped into action over the weekend.
As it was my first application and it was for internal use, I limited myself to the below feature list:
- multi-user system with login/logoff
- micro-blog (<= 150 characters per blog)
- groups (something similar to threads; a provision for related conversation)
- Active Directory authentication (so there was no need for user registration)
I decided to take up AD authentication later. I understood from Django forum that it was possible to plug-in that feature.
I looked for a ‘cool’ name for the application. Being a micro-blog, I wanted a simple, single syllable word that represents word or conversation or talk. I settled with ‘SOL’ – it is a Tamil word representing what I expected.
Typical Django applications consists of models (classes), views (logic) and templates (presentation). URLs bind all of these components together.
Models
It seemed logical to start with models – one for SOLs and another one for group. There is nothing complex here; pretty simple models. I also built form models for each of these. So here is models.py:
class group(models.Model): desc = models.TextField(max_length=25) def __unicode__(self): return unicode(self.id) def get_absolute_url(self): return "/g/%s" % unicode(self.id) class Admin: list_display = ('id','desc') class Meta: ordering = ['-id'] class sol(models.Model): body = models.TextField(max_length=150) author = models.ForeignKey(auth.User) date = models.DateTimeField('Date') group = models.ForeignKey(group) def __unicode__(self): return unicode(self.id) def get_absolute_url(self): return "/sol/%s/" % unicode(self.id) def get_author_url(self): return "/u/%s/p/0" % (self.author) class Admin: list_display = ('author', 'body', 'date') date_hierarchy = 'date' class Meta: ordering = ['-date'] class solForm(ModelForm): body = forms.CharField(max_length=150, widget=forms.Textarea(attrs={'rows':2, 'cols': 40}),label= 'Your Sol:') author = forms.CharField(widget=forms.HiddenInput) date = forms.CharField(widget=forms.HiddenInput) group = forms.CharField(widget=forms.HiddenInput) class Meta: model = sol class grpForm(ModelForm): desc = forms.CharField(max_length=25, label= 'Create Your Group:') class Meta: model = group
Views
There are only three functions (or views):
- create a group
- create a SOL
- display list of SOLs (for groups, users, and all)
It is so simple to display list of SOLs (for that matter any objects). Django provides generic views for that. However I used my own views. All that is needed is the template name and a dictionary of values to be passed to the template.
Object (user or group or a default home page), object id, template name, and page number are passed to the view function; each variable also have default values. Using ObjectPaginator, these objects are paginated. Here is my views.py:
#for pagination: http://www.slideshare.net/simon/the-django-web-application-framework/# #generic view function for homepage (solhome), userhome and group home #object is one of the param; object="u" -> user; g->group; s->sol, which is default home page #object id : for u & g the respective ids; for sol nothing; defaults to sol(0) #pagenum : for pagination; default is 0 otherwise the pagenumber to be displayed in the input def home(request, model="s",objectId="0",page_num=0, template='home.html'): paginate_by = settings.PAGINATE_BY #what we get as parameter is always a string page_num = int(page_num) if model == 'u': #for user we need to filter for the user info_list = ObjectPaginator(sol.objects.all().filter(author__username=objectId),paginate_by) elif model== 's': #for sol; home page info_list = ObjectPaginator(sol.objects.all(),paginate_by) elif model =='g': #for group if objectId == '0': info_list = ObjectPaginator(group.objects.all(),paginate_by) else: info_list = ObjectPaginator(sol.objects.all().filter(group=group.objects.get(id=objectId)),paginate_by) has_previous = info_list.has_previous_page(page_num) has_next = info_list.has_next_page(page_num) info_dict = { 'query_list' : info_list.get_page(page_num), 'has_previous' : has_previous, 'previous_page' : page_num - 1, 'has_next' : has_next, 'next_page' : page_num + 1, 'site_name' : 'sol', 'user' : request.user, } if model == 's': form = solForm() #this is how you append to a dict info_dict['solForm'] = form if model == 'u': #this is how you append to a dict info_dict['u_id'] = objectId info_dict['nickname'] = userprofile.objects.get(user__username=objectId).nickname if model == 'g': info_dict['grpForm'] = grpForm() if objectId == '0': info_dict['solForm'] = solForm() else: info_dict['solForm'] = solForm(initial={'group': group.objects.get(id=objectId)}) info_dict['grpName'] = group.objects.get(id=objectId).desc return render_to_response(template, info_dict) def logout(request): auth.logout(request) return HttpResponseRedirect('/') def createsol(request): #if there is nothing in the text field, do nothing if request.POST['body'] == "": return HttpResponseRedirect('/') newsol = sol() newsol.author = request.user newsol.date = datetime.datetime.today() newsol.body = request.POST['body'] if request.POST['group'] <> '': newsol.group = group.objects.get(id=request.POST['group']) newsol.save() return HttpResponseRedirect('/') def creategroup(request): if request.POST['desc'] == "": return HttpResponseRedirect('/groups/') newgrp = group() newgrp.desc = request.POST['desc'] newgrp.save() return HttpResponseRedirect('/groups/') def help(request): return render_to_response('help.html')
SOL URLs:
URLs are the routing engines connecting both models and views. The URLs for SOL are:
- homepage (of sol) – listing all SOLs
- user’s homepage – SOLs of a particular user
- group homepage – SOLs belonging to a particular group
- creation of new sol
- creation of new group
With support for pagination and admin, url.py is like:
urlpatterns = patterns('cool.sol.views',
#default page number is 0;
#url like: http://sol.com/
(r'^$', 'home'),
#homepage for sol with pagination enabled
#url like: http://sol.com/p/0
(r'^p/(?P<page_num>d+)/$', 'home',{'template':'home.html', 'model':'s'}),
#user homepage - employees with employee ids as numbers;
#url like: http://sol.com/u/1029/p/0
(r'^u/(?P<objectId>d+)/p/(?P<page_num>d+)/$', 'home',{'template':'user_home.html', 'model':'u'}),
#groups homepage
#url like: http://sol.com/groups/ or http://sol.com/groups/p/0
(r'^groups/$', 'home',{'template':'groups_home.html', 'model':'g'}),
(r'^groups/p/(?P<page_num>d+)/$', 'home',{'template':'groups_home.html', 'model':'g'}),
#homepage for a particular group
#url like: http://sol.com/g/100/p/0
(r'^g/(?P<objectId>d+)/$', 'home',{'template':'group_home.html', 'model':'g'}),
(r'^g/(?P<objectId>d+)/p/(?P<page_num>d+)/$', 'home',{'template':'group_home.html', 'model':'g'}),
#logoff
(r'^logout/$', 'logout'),
#create a sol; called by form action
(r'^createsol/$', 'createsol'),
#create a sol; called by form action
(r'^creategroup/$', 'creategroup'),
#help
(r'^help/$', 'help'),
)
#these are derived from admin
urlpatterns += patterns('',
#login page
(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
#admin page
(r'^admin/', include('django.contrib.admin.urls')),
)
Templates
Only thing left are templates. Django templates can be inherited. Hence first you define the basic template with placeholder blocks – for html headers, page headers like navigation menus and footer – then build upon that template until the final template. It is okay to fill-in only few blocks.
Here is a snippet from base.html.
<div id="content"> <div id="left"> {% block content %} {% block newgroup %} {% endblock %} {% block newsol %} {% endblock %} {% block entries%} {% endblock %} {% block paginate %} {% endblock %} {% endblock %} </div> <div id="footer"> {% block footer %}{% endblock %} </div> </div>
Now in home.html, I derive from base.html and define what is needed:
{# Template for home page for sol; it lists all the sols #}
{% extends "base.html" %}
{% block newsol %}
{% if user.is_authenticated %}
<div class="form">
<form action="/createsol/" method="post" enctype="multipart/form-data">
<table>
{{ solForm }}
</table>
<input type="submit" value="Update" />
</form>
</div>
{% endif %}
{% endblock newsol%}
Once you get these concepts (model, view, template and urls), it is extremely easy to put together a website.
The complete code can be downloaded from google code page.
(Note: There might be a better way to do all of this. As I read more and write more of Django, I hope to figure them out. However, if there is a better way, there is no harm in leaving a comment about the same.)








