views:

117

answers:

1

I have a webapp that lists all of my artists, albums and songs when the appropriate link is clicked. I make extensive use of generic views (object_list/detail) and named urls but I am coming across an annoyance. I have three templates that pretty much output the exact same html that look just like this:

{% extends "base.html" %}
{% block content %}
<div id="content">

<ul id="starts-with">
{% for starts_with in starts_with_list %}
    <li><a href="{% url song_list_x starts_with %}">{{ starts_with|upper }}</a></li>
{% endfor %}
</ul>

<ul>
{% for song in songs_list %}
    <li>{{ song.title }}</li>
{% endfor %}
</ul>

</div>
{% endblock content %}

My artist and album template look pretty much the same and I'd like to combine the three template's into one. The fact that my variables start with song can easily be changed to the default obj. It's my <ul id="starts-with"> named url I don't know how to correct. Obviously I want it to link to a specific album/artist/song using the named urls in my urls.py but I don't know how to make it context aware. Any suggestions?

urls.py:

urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
    # (r'^$', index),
    url(r'^artists/$', artist_list, name='artist_list'),
    url(r'^artists/(?P<starts_with>\w)/$', artist_list, name='artist_list_x'),
    url(r'^artist/(?P<artist_id>\d+)/$', artist_detail, name='artist_detail'),
    url(r'^albums/$', album_list, name='album_list'),
    url(r'^albums/(?P<starts_with>\w)/$', album_list, name='album_list_x'),
    url(r'^album/(?P<album_id>\w)/$', album_detail, name='album_detail'),
    url(r'^songs/$', song_list, name='song_list'),
    url(r'^songs/(?P<starts_with>\w)/$', song_list, name='song_list_x'),
    url(r'^song/(?P<song_id>\w)/$', song_detail, name='song_detail'),
)
+2  A: 

You could define url patterns for a generic object_type instead of individually for artists, albums and songs:

urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
    # (r'^$', index),
    url(r'^(?P<object_type>\w+)/$', music_object_list, name='music_object_list'),
    url(r'^(?P<object_type>\w+)/(?P<starts_with>\w)/$', music_object_list, name='music_object_list_x'),
    url(r'^(?P<object_type>\w+)/(?P<object_id>\d+)/$', music_object_detail, name='music_object_detail'),

)

Then in your template, your url tag becomes

{% url music_object_list_x object_type starts_with %} *

You may find you only need one view, music_object_list. If you find you need different functions for each object type, then call the individual functions in music_object_list.

def music_object_list(request, object_type, starts_with=None):
     if object_type == 'artists':
         return artist_list(request, starts_with=starts_with)
     elif object_type == 'albums':
         return album_list(request, starts_with=starts_with)
     ...

If you are using django.views.generic.list_detail.object_list, then remember to add object_type to the extra_context dictionary. This will add object_type to the template context, allowing the url tag to work.

extra_context = {'object_type': 'songs', ...}

* This is the new url tag syntax for Django 1.2. For older versions you would use a comma.

{% url music_object_list_x object_type,starts_with %}

See the docs (Current, 1.1) for more information

Alasdair
I like where this is going! I am trying to see how this is working as we speak. If this goes according to plan I will be forever grateful. The only thing I would change is using `object_list` as a function name seems to be conflicting with `from django.views.generic.list_detail import object_list` but that's easily overcome. I'll be back with my findings!
TheLizardKing
Good point about the name conflict. I've renamed the function to `music_object_list`.
Alasdair
I think I am having a hard time getting the `{% url music_object_list_x object_type,starts_with %}` to recognize the object_type in my template. I am on Django 1.1.1
TheLizardKing
Haha, whoops. I should of added my views but I fixed it by passing it through my `extra_context = {'starts_with_list': starts_with_list, 'object_type': 'songs'}`
TheLizardKing
I can all ready tell this is exactly what I need. Thanks!
TheLizardKing
You're welcome. I updated my answer to mention adding `object_type` to `extra_context`, but I see you worked it out already!
Alasdair