I confess, I've fallen for the Django framework. It's the most straightforward, hassle free web framework I've used to date and it's the firm foundations of Napes.co.uk. Now I'm sharing the knowledge with fellow n00bs. This tutorial explains how to implement tagging across your project using the much coveted django-tagging framework including tag clouds and filters.
This tutorial was written using a version of Django which is now deprecated and therefore certain parts of the tutorial may not work with the latest version of the framework.
This article uses the much coveted django-tagging package to implement tagging. You should have it installed already before you begin. By the end of this tutorial you'll be able to:
The code snippets in this tutorial are based on the code used to host this website and will focus on adding tags to blog articles. However, the same concepts apply to all models and I have successfully implemented them in my photos application as well.
Before starting, make sure you have imported the tagging application in your settings.py file so that INSTALLED_APPS contains 'tagging'.
We begin by modifying the models for the objects we wish to tag. Tags in django-tagging are common to all models and so the same method can be applied to each of the models you want to tag. For simplicity's sake this article only implements tag browsing on a per-model basis.
To add tagging to a model (<appname>/models.py) import the tagging package, add a tag field, and declare a get_tags method as shown below.
from django.db import models
import datetime
from tagging.fields import TagField
from tagging.models import Tag
class BlogEntry(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True, prepopulate_from=('title',))
date = models.DateTimeField(default=datetime.datetime.now)
tags = TagField()
html = models.BooleanField(default=False)
def get_tags(self):
return Tag.objects.get_for_object(self)
Some models will have an existing tag field in which case, you shouldn't add another. TagField() is a tokenized field, in the admin interface it will appear as a single line text field, however, each word will represent a different tag in the database.
You should now run python manage.py syncdb to create the tagging tables in your database. Since tags are held in an external table there is no need to update your model table manually.
Ensure your server is started (python manage.py runserver for the development server) and load your administration control panel (http://localhost:8000/admin/). If you create or edit the model you have been working on you should now see a tags field where you can enter tags for the entry. Try adding some tags to an existing or new item, when you return to the admin homepage you should be able to see them in the Tags collection.
While it's possible to create tags that are capitalise or contain more than one word, for example "New York" this will cause problems when we want to convert to and from slugified versions of the tag (versions that can be used as urls). For this tutorial, I recommend using simple, single word tags using hyphens, for example new-york.
Template tags allow templates to contain information from other applications without having to explicitly define it in the views.py file. Template tags are usually placed in a templatetags directory under the application they are associated with. Since our tags can be associated with any model, I created a new application 'misc' to store any generic applcation files. This is simply a directory under the project directory and a templatetags directory under that. Both should contain a __init__.py file (which can be empty). As with all Django applcations it should also be added to the settings.py file so that INSTALLED_APPS contains 'misc'.
Create a new file inside templatetags called tag_cloud.py. Copy and paste (or create a link to) the contents of django-tagging/tagging/templatetags/tagging_tags.py. This contains the code we will need for creating tag clouds.
{% load tag_cloud %}
{% tag_cloud_for_model blog.BlogEntry as tags with steps=6 min_count=1 distribution=log %}
{% for tag in tags %}
{{tag.name}} ({{tag.font_size}})
{% endfor %}
This will list all the tags in the model blog.BlogEntry along with their 'weighting'. You should change the model to the one you are using in your project in the form <appname>.<ModelName>. In this example, the weighting varies by six degrees, corresponding to the steps=6 declaration.
This is a fairly awful tag cloud, however, we now have the basic fixtures in place.
To ensure that readers can view all the tags for your site, or to allow them to browse items by tags, we will create a set of views specifically for tagging.
First, edit the urls.py file for your application to include the views for the tags as shown below.
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^tags/$', 'blog.views.tags'),
(r'^tag/(?P[-_A-Za-z0-9]+)/$','blog.views.with_tag'),
(r'^tag/(?P[-_A-Za-z0-9]+)/page/(?Pd+)/$', 'blog.views.with_tag' ),
)
Note that this does not show all the views for this application and you will likely have several more which you should not remove. As always you should adjust the names of the views to match the name of your application.
Start editing your views.py file for the application you are adding tags to. Import the tagging packages and add two methods, tags and with_tag along side any existing views you may have as shown below.
import django.http as http
import django.shortcuts as shortcuts
from tagging.models import Tag, TaggedItem
import models
def tags(request):
return shortcuts.render_to_response("blog/tags.html")
def with_tag(request, tag, object_id=None, page=1):
query_tag = Tag.objects.get(name=tag)
entries = TaggedItem.objects.get_by_model(models.BlogEntry, query_tag)
entries = entries.order_by('-date')
return shortcuts.render_to_response("blog/with_tag.html", dict(tag=tag, entries=entries))
Be sure to edit the model names and template locations to match those of your application.
Now that the urls and views are in place we can begin the last, and most rewarding step - creating the templates. We will have three templates to add to our project, inc/tag_cloud.html for showing inline tag clouds, tags.html for showing the complete tag cloud and with_tag.html for showing entries with a specific tag. I have also created a style-sheet to better present the tag clouds.
Note that you will have to surround these templates with valid html for them to work, since most django sites use a base template file I decided not to include all the html cruft. You will also, as always have to edit model and application names to match your project.
Firstly, tags.html:
<h1>Blog Tags</h1>
<div class="tag-cloud">
{% load tag_cloud %}
{% tag_cloud_for_model blog.BlogEntry as tags with steps=6 distribution=log %}
{% for tag in tags %}
<span class="tag-{{tag.font_size|add:"2"}}"><a href="/blog/tag/{{tag.name|slugify}}/">{{tag.name}}</a></span>
{% endfor %}
</div><!-- tag-cloud end -->
Secondly, with_tag.html:
<h1>Blog Tag Search</h1>
<p>You searched the blog entries for the tag <span class="highlight">{{tag}}</span>.</p>
{% if entries %}
{% for entry in entries %}
<div class="row-{% cycle odd,even %}">
<h2><a href="/blog/{{entry.slug}}/">{{entry.title}}</a></h2>
<h3>{{entry.date|date:"jS F Y"}}</h3>
{{entry.precis|safe|linebreaks}}
{% if entry.content %}
{% endif %}
</div><!-- row end -->
{% endfor %}
{% else %}
<p>No articles have that tag</p>
{% endif %}
Lastly, inc/tag_cloud.html. I have this as a separate file so that I can include it in other pages, such as the blog summary and search pages, and maintain it in a single location. To include files in your templates, use {% include 'blog/inc/tag_cloud.html' %}
<h2>Blog Tags</h2>
<div class="tag-cloud">
{% load tag_cloud %}
{% tag_cloud_for_model blog.BlogEntry as tags with steps=6 min_count=1 distribution=log %}
{% for tag in tags %}
<span class="tag-{{tag.font_size}}"><a href="/blog/tag/{{tag.name|slugify}}/">{{tag.name}}</a></span>
{% endfor %}
</div><!-- tag-cloud end -->
<p><em>View the <a href="/blog/tags/">whole tag cloud</a></em></p>
On some pages, you may wish to display the tags for a single item rather than the entire collection. This can also be done using the tag_cloud template tag:
<h2>This Article's Tags</h2>
<div class="tag-cloud">
{% load tag_cloud %}
{% tags_for_object entry as tags %}
{% for tag in tags %}
<a href="/blog/tags/{{tag.name|slugify}}/">{{tag.name}}</a>
{% endfor %}
</div><!-- tag-cloud end -->
<p><em>View the <a href="/blog/tags">whole tag cloud</a></em></p>
As a bonus, here's that style-sheet I was talking about:
.tag-cloud {
text-align: center;
border: 1px solid #FFFF00;
padding: 5px;
background-color: #FFFFCC;
}
.tag-1 {
font-size: 12px;
}
.tag-2 {
font-size: 13px;
}
.tag-3 {
font-size: 14px;
}
.tag-4 {
font-size: 15px;
}
.tag-5 {
font-size: 16px;
}
.tag-6 {
font-size: 17px;
}
/* For large tag cloud 6 step */
.tag-7 {
font-size: 18px;
}
.tag-8 {
font-size: 19px;
}
Hopefully this explains some of the concepts behind django-tagging and gives you a feel to integrate tag clouds and tagging into all the models you want.
Thanks. Out-of-date or not, you definitely helped this n00b.
20 Nov 2008Hey, great tutorial highlighting the oft-confusing template tag syntax. I've got a correction and an update to your 'with_tag' function in views.py:
1) The line defining your 'entries' queryset should end with:
*.get_by_model(models.BlogEntry, query_tag)
which utilizes the 'query_tag' from the previous line, instead of just the 'tag' string.
2) To enable multi-word tags, simply add:
from re import sub
tag = sub('-',' ',tag)
as the first two lines of your function.
Great work, cheers!
09 Dec 2008thanks a lot for this introduction
21 Jan 2009helped antoher django-beginner to make django-tagging work.. =))
Great tutorial!
Thank you very much to a great tutorial in using the django-tagging application.
Keep up the good work.
30 Apr 2009Thanks for the words of support!
Also, thank you Andrew for your correction, I have updated the article.
02 May 2009Great work. Thanks a lot. I could make the basic tagging framework work :)
18 Aug 2009Hooray! Finally I know how to use it!!
01 Jan 2010No need to copy/paste the template tags. If you installed django-tagging app, you can load the tagging tag like this :
{% load tagging_tags %}
16 Jan 2010Thanks for sharing this with other django n00bs like me :-).
24 Feb 2010Hi...
I am following alla the step but
I have some problem with the URL.. it return an error ("unknown specifier: ?P[") when put "localhost:8000" in my browser. Why?
in any don't undestand how i have to change this "test code"
{% load tag_cloud %}
24 Feb 2010{% tag_cloud_for_model blog.BlogEntry as tags with steps=6 min_count=1 distribution=log %}
{% for tag in tags %}
{{tag.name}} ({{tag.font_size}})
{% endfor %}
SOLVED!
01 Mar 2010Hi,everyone!!! I'm glad that came across your site because here I can find always useful and helpful news. I learned a lot of wholesome information.Your site is awesome and very popular.
07 Jul 2010you have access to your servers config files, check if the following line is commented out in the load modules ……
20 Jul 2010yes that's correct. that would save your considerable time in detecting whether there are problems in your server config files
21 Jul 2010