Loading...

Simple django-tagging HOWTO

January 25, 2008 1 Comment Tagged as: django django-tagging howto python

After looking through my Google Analytics results, I noticed that a few hits to my site were people looking for a howto on integrating django-tagging, which I have been wanting to write for quite some time. While I'm quite experienced working with SQL schemas and the like, there were some ORM concepts that I had never been exposed to until I started using Django (it was my first framework featuring an ORM). Things like Generics confused me, although I knew how to do something similar in plain ol' SQL, it took me a bit to grasp the concepts. So I figure a good way to demonstrate their uses, along with demonstrating integrating django-tagging into an app would be a fine use of my precious blog space...

Please keep in mind that I am not a Django expert, nor am I a django-tagging expert. My experience with django-tagging has been adding it to my blog posts. While I've considered making an entire category hierarchy-type site with tags, I haven't actually implemented it. All I can demonstrate on the basics. You'll have to learn the rest on your own. Also, it's important to point out that I have been using the svn version of django-tagging, although recently, a 0.2 version was released. I just set up my project's svn to use externals and keep me up to date on django-tagging.

First thing's first, you need a model. I'm going to use a dumbed down version of the model I use for blog posts. Lay out your model like this:

from django.db import models

class BlogPost(models.Model):

    title = models.CharField(max_length=30)
    body = models.TextField()
    date_posted = models.DateField(auto_now_add=True)

Now you have a pretty simple blog class. After a syncdb, you can fire up the admin app and start blogging! Er, kinda. You won't have any way for a user to see your posts, but you'll have posts in the database. However, you've got no tags! How would you implement tags into your new fangled blog? Easy. Download the tagging module and install it (I usually just copy the appropriate files to my $PYTHONPATH). Then it's actually quite simple, and you'll kick yourself for not figuring this out. Modify your blog model, and add this:

from django.db import models
from tagging.fields import TagField

class BlogPost(models.Model):

    title = models.CharField(max_length=30)
    body = models.TextField()
    date_posted = models.DateField(auto_now_add=True)
    tags = TagField()

However, you're going to want a method in your model that will allow you to iterate through the tags, called get_tags. I also have a set_tags method, and I know there was a reason I added that, I just can't remember what it was... (a good case for why you should always comment your code). So modify your model so that it now looks like this:

from django.db import models
from tagging.fields import TagField
from tagging.models import Tag

class BlogPost(models.Model):

    title = models.CharField(max_length=30)
    body = models.TextField()
    date_posted = models.DateField(auto_now_add=True)
    tags = TagField()
    
    def set_tags(self, tags):
        Tag.objects.update_tags(self, tags)

    def get_tags(self, tags):
        return Tag.objects.get_for_object(self)      

Now you've got a full blown model with tagging built in. Make sure you've got tagging installed in your INSTALLED_APPS, blow out your database, and syncdb again. Hooray! You'll notice on my blog that I have the tags shown at the top of each post, which is accomplished by with the following template code:

{% for tag in blogpost.get_tags %}
  <a href="/blog/tag/{{tag}}" alt="{{tag}}" title="{{tag}}">{{tag}}</a>
{%endfor%}

I know there are template tags for many of the standard operations for django-tagging, but I haven't used any of them. I noticed that most of them are for tag clouds by model or object, and I would like a tag cloud period, with links to pages on the site with various items that are tagged with the given tag. I have just been far too lazy to actually implement it yet, but there is a weekend coming up...

Edit: I've found some better ways to implement django-tagging, so I've made some changes to this tutorial

Django People and Me

January 23, 2008 No Comments Tagged as: django

Simon Willison and Natalie Down were quite kind enough to create Django People. I signed up, and my profile can be found here.

One thing that has never ceased to amaze me about Django is the wonderful community. We have great sites like Django Snippets and Django Gigs and now the Django People. These are all grassroots efforts from people who just love Django

I did, however, find it odd that something Simon Willison made didn't include OpenID authentication...

Comments Now Live!

November 5, 2007 1 Comment Tagged as: django theironlion

I finally got around to creating a good comment system in Django. It wasn't necessarily hard, I just didn't have time for to read all of the documentation. After reading "The Pragmatic Programmer," I was insistent that since I was already working on other pieces of the site that will also warrant commenting, I would need to create a commenting system that's easily ported to other parts of the site (DRY). While this is a simple task to create at the database level, I needed to utilize Django's tools to create the relationships.

What finally ended up happening was that I needed to use Generic Relations. This became an easier task when I got around to reading the documentation. I also started to feel the pinch of models and database tables becoming out of sync, which caused a lot of problems. That's the biggest flaw in Django. However, I have yet to see a good framework that handles it well.

These problems are the best reason that you should rarely use a framework to perform actions automatically when you don't understand the underpinnings (I use the word rarely because frankly, C compilers are about as low level as I care to go).

Experience Renaming Deployed Django Apps

October 16, 2007 4 Comments Tagged as: django django-tagging howto refactoring

I've released yet another iteration of The Iron Lion, with the key of this new release being my new knowledge of the newforms library. I've been thinking about adding the ability to comment for a while, and have even blogged about some of the ideas I've had/seen to reduce spam and the like. You'll find the new contact form to be my experiment with the newforms library (and also a solution to putting my email out on the web, even though I've gotten plenty of spam in the email address anyway).

After I pushed this new version, I decided that my naming scheme for my various apps was becoming cumbersome more than clever. I was naming the different apps after planets in our solar system. Cute naming convention, but since this is becoming more than just a few apps, I found it difficult to remember what neptune was, why I need the earth app in this situation, and what pluto was even created for. So I obviously needed to rename these apps.

I was expecting that the process was just a matter of renaming the folders. There were obvious dependencies to worry about, and import calls to fix. So I started by moving the folders around. I then did an fgrep for all the instances of the old names. Using sed, I did a search and replace of each name. For some reason after that, my Django dev server didn't much like the environment variables I had set, and so I had to work out some problems with my environment before I could test it...

One day later, and I was back to work. I browsed around the dev server, to make sure everything was working, and noticed only one thing broken: Tags. This was an opportunity I had been waiting for, actually, and I dove headfirst into the tag database schema. The tags for this site are generated with the django-tagging app, and so I didn't have much experience with generic relations and the like, and I wanted to. I found a table called 'tagged_item' which I invesitigated, and found a reference to a content type id. I figured it must be the django_content_type foreign key, and kept digging. Apparently, django keeps a database of all the installed models, and the apps they are connected to. A few updates later, and I had tags working!

So, in summary, if you want to rename a Django app that's deployed in the field:

  1. Rename the folder found in your project root
  2. Change any references to your app in their dependencies, i.e. the app's views, the urls.py and settings.py files.
  3. Edit the database table django_content_type with the following command: UPDATE django_content_type SET app_label='<NewAppName>' WHERE app_label='<OldAppName>' (Note: for renaming models, you'll need to change django_content_type.name)

Sensationalism Is Not Synonomous With Advocacy

September 24, 2007 Tagged as: best-practices django php rails

I read a great article by Derek Silvers entitled 7 reasons I switched back to PHP after 2 years on Rails. I've heard just too many "silver bullet" schpiels about X language, or Y framework. Granted, I've got the tools I draw like a gun in the heat of the moment, but just because it works for me, doesn't mean it works for everyone.

I stayed away from Ruby, and particularly Rails, mostly because of the sensationalism. Yes, I did work with it, and I never found anything that gave me an advantage of Python, but it was ultimately the amount of community hatred for anything else that kept me from taking Rails seriously. The ignorance I found in the Rails IRC channels and mailing lists was a major turnoff. There are fanboys and sensationalists in every language, but I found a concentration of them in the Ruby on Rails community.

And this post on Slashdot is why I stopped reading Slashdot a long time ago...

And then my feelings were expressed oh so eloquently in this post by Jamie Flourney. One of the points that really stuck out to me is made is that sometimes writing SQL is a better way to go. Using Django, I was exposed to ORMs for the first time, and while I liked it, I will admit it made me uncomfortable, but it was a new approach. The question though is "Does it really solve the problem at hand?" Django solves most of my problems for my personal site, but it won't fit in some of my other web applications, and that should be understandable. If a tool doesn't work in a particular situation, that doesn't mean the situation is broken.

Open Source Iron Lion

August 27, 2007 Tagged as: django open-source python source-code

I've finally gotten around to finishing up the third version of The Iron Lion. It's been quite a pleasure to work with Django, and I've seen the light of a good python framework. I feel pretty confident in the work I've done for this site, and as such, I've decided to publish the source for it. There are some out of date tests and docs in there (which is only because it's my own project, so I've been lax there.

The next step for me is to integrate that nice django tagging module, as well as using epydoc to document my code and the doctest and unittest modules from the standard library to get proper code coverage.

The source can be found here

Dreamhost, Django, and Site Statistics

July 10, 2007 Tagged as: django dreamhost python

I followed Jeff Croft's Howto to install Django with Dreamhost, my hosting provider. This works well, and, while I didn't follow his instructions to the letter, I followed it close enough to know how the underpinnings worked. I've gone through now three revisions of my software, each time, being careful not to step on my Django installation (which is trivial). As you can see from my site, it works well.

Today I ran into a snafu. Dreamhost uses Analog 6.0 to provide simple web statistics. I've been having a hard time implementing my Google Analytics middleware with Django, so I decided I'd use the Analog stuff for now. However, when I navigate to the statistics url page, the FCGI dispatcher I use with Django grabs the request, and handles it as a 404 error. After reading an entirely too much about Apache redirects, I finally figured it out. If you follow Jeff Croft's .htaccess instructions, your file should look like this:


RewriteEngine On
RewriteBase /
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(admin_media/.*)$ - [L]
RewriteRule ^(dispatch\.fcgi/.*)$ - [L]
RewriteRule ^(.*)$ dispatch.fcgi/$1 [L]

The trouble occurs because you must specify what url strings aren't handled by the dispatch.fcgi file, and everything else will be handled by it. So I added one line to the .htaccess file that would fix the Dreamhost stats for me, so it now looks like this:


RewriteEngine On
RewriteBase /
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(admin_media/.*)$ - [L]
RewriteRule ^(dispatch\.fcgi/.*)$ - [L]
RewriteCond %{REQUEST_URI} ^/stats/(.*)$ [OR]
RewriteRule ^(.*)$ dispatch.fcgi/$1 [L]

Thank goodness for stats! The result is the knowledge that The Iron Lion is growing very rapidly! Soon there will be more features here, and I'll also be releasing another tarball of the entire site.