The basics of creating a tumblelog with Django (part 2)

In The basics of creating a tumblelog with Django, I took my first shot at walking others through some helpful code, in this case the basic programming patterns to use when creating a tumblelog with Django. Since posting this entry, I’ve received some requests to explain how to get these tumblelog items to actually show up on my homepage. Since my target audience is someone relatively new to Django, or even new to programming, I should have included this in the original entry.

This walk-thru picks up where the original left off, with generic StreamItem objects pointing to various Bookmarks, Statuses, and FreeComments. Each StreamItem object, in addition to keeping track of when the original item was published, also has a get_rendered_html method which passes the original object into a template and provides the resulting output. The StreamItem class and the functions that create StreamItems are kept in the models.py file of an app called ‘stream.’

Now lets get these items onto the homepage.

The first step is to determine what URL, when entered, will show these items. Since we’re putting these on our homepage, the url is just “/”. So in the urls.py file, we want to match a URL that begins and ends with “/” and execute the ‘homepage’ function in views.py.

1
2
3
4
5
from django.conf.urls.defaults import *

urlpatterns = patterns('',
	(r'^$', 'stream.views.homepage'),
)

The line in the urlpatterns is a regular expression. ‘^’ roughly means, “at the beginning,” and “$” roughly means “at the end.” Since there’s nothing between the beginning and the end, this URL will match http://example.com/ and run the homepage() method in stream/views.py. Let’s take a look at this method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from stream.models import StreamItem
from django.shortcuts import render_to_response

def homepage(request):
	
	context = {
		'stream_item_list': StreamItem.objects.all().order_by('-pub_date')[:10]
	}
	
	return render_to_response('stream/homepage.html', context)

We create a dictionary named ‘context’, which contains a variable named ‘stream_item_list,’ which gets a list of the latest 10 StreamItems sorted by their ‘pub_date’ field, newest to oldest. This dictionary is then passed to the render_to_response function, along with a template name that will be rendered with access to any variable set in the context. homepage.html contains this:

1
2
3
{% for stream_item in stream_item_list %}
	{{ stream_item.get_rendered_html }}
{% endfor %}

It loops through each item in the list, and outputs each item’s get_rendered_html method, which passes that item’s referenced object, a Bookmark for example, to a template. This method can be seen in the original tutorial. Finishing our Bookmark example, here’s the template that each Bookmark is rendered with.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{% load comments %}
{% get_free_comment_count for blog.bookmark object.id as comment_count %}
<div class="stream_link">
	<div class="stream_item">
		<a href="{{ object.get_absolute_url }}" title="View more about this link" class="icon icon_link">View more about this link</a>
		<h4><a href="{{ object.href }}" title="{{ object.title }}">{{ object.title }}</a></h4>
		<h5>{{ object.time|date:"F jS Y, P" }} // <a href="{{ object.get_absolute_url }}#discussion" title="View comments for {{ object.title }} ">{{ comment_count }} comment{{ comment_count|pluralize }}</a></h5>
		{% load markup %}
		{{ object.extended|markdown }}
	</div><!-- End .stream_item -->
</div><!-- End .stream_link -->

I hope this helps clear up any questions, and if it raises any more, please leave them in the comments.


Discussion
Link to this comment

Once again you've hit the nail on the head.

I've actually got code (courtesy of Christian) lying around for a template tag that does the equivalent of your get_rendered_html() method, and I've found it to be a wonderfully flexible solution.

July 2nd 2008, 3:34 a.m. by James Bennett
Link to this comment

Something interesting might be to have a few methods for rendering HTML, so you could have 1 for the main screen, and perhaps another for the sidebar. I believe Honza Kraal did something like that with the news system he and his company created(it's open sourced somewhere).

July 2nd 2008, 3:47 a.m. by Alex
Link to this comment

I'm going to pimp a project of mine that probably does something like James is mentioning:

http://code.google.com/p/django-representations/

July 2nd 2008, 8:16 a.m. by Eric Moritz
Link to this comment

James, a template tag to do this would definitely be more flexible in the long run. I never liked that my method for getting HTML was tied to the model.

Alex, in that case, it would certainly be a good idea to move this code out of the model and use it more generically, like in a template tag. Though I guess using the method does allow all the code to stay in one place and is maybe a bit easier to follow?

Eric, you just have something up your sleeve for all my problems, don't ya? Two questions though, regarding using django-representations in a situation like this:

  1. In my template, would I have to use ifequal tags to determine which template to render my object with?

  2. And if that's the case, what advantage does it have over the include tag?

It seems like django-representations is ideally suited for a situation like a search result, or your more consistent feed items from feedclowd, that all have the same fields. Or am I missing something?

July 2nd 2008, 9:54 a.m. by Ryan Berg
Link to this comment

Thanks for the 2nd part of this tutorial. I actually got this running with some help of people in #Django.

In my case I used a generic view to get the job done. I think it would be great to someday get a template tag or something else to do this. It seems like a long process to go through just to combine a couple of models. I know this process doesn't exist right now, but wouldn't it be neat if we could make 1 queryset on multiple models? Then when we create the model we could have some type of contenttype field that would save automatically and when we render it to the template we could just do ifequal to determine what to display based on content.

July 2nd 2008, 2:13 p.m. by Jason Broyles

Comments are disabled for this item