views:

91

answers:

3

I have a many to many relationship in my models and i'm trying to reorganize it on one of my pages.

My site has videos. On each video's page i'm trying to list the actors that are in that video with links to each time they are in the video(the links will skip to that part of the video)

Here's an illustration


Flash Video embedded here

Actors...

Ted smith: 1:25, 5:30
jon jones: 5:00, 2:00

Here are the pertinent parts of my models

class Video(models.Model):
    actor = models.ManyToManyField( Actor, through='Actor_Video' )
    # more stuff removed

class Actor_Video(models.Model):
    actor = models.ForeignKey( Actor )
    video = models.ForeignKey( Video)
    time = models.IntegerField()

Here's what my Actor_Video table looks like, maybe it will be easier to see what im doing

id     actor_id    video_id    time (in seconds)
1        1             3        34
2        1             3        90

i feel like i have to reorganize the info in my view, but i cant figure it out. It doesn't seem to be possible in the template using djangos orm. I've tried a couple things with creating dictionaries/lists but i've had no luck. Any help is appreciated. Thanks.

A: 

I fashioned it into a dictionary of time lists

actor_sets = data['video'].video_actor_set.all()
data['actors'] = {}

for actor_set in actor_sets:
    if not data['actors'].has_key( actor_set.actor ):
        data['actors'][actor_set.actor] = []
        data['actors'][actor_set.actor].append( actor_set.time )

And in the template i looped over that instead of running the queries in the actual template

Galen
A: 

I would suggest putting your logic in the view function rather than the template. If I understand correctly, on each page you have only one video, which makes things reasonably simple

def video_view(request,video_id)
    video = Video.objects.get(pk=video_id)
    actors = Actor.objects.filter(video=video)
    #now add a custom property to each actor called times
    #which represents a sorted list of times they appear in this video
    for actor in actors:
        actor.times = [at.time for at in actor.actor_video_set.filter(video=video).order_by('time')] #check syntax here

then in the template, you can just loop through actor.times:

<ul>
{% for actor in video.actors.all.distinct %}
    <li>{{ actor }}:

        <ul>
    {% for t in actor.times %} #this now returns only the times corresponding to this actor/video
            <li><a href="?time={{ t.time }}">{{ t.time }}</a></li> #these are now sorted

NB - wrote all the code here without using an IDE, you'll need to check syntax. hope it helps!

for bonus points: define a times(video) function as a custom function of the Actor model class

hwjp
A: 

I think the most Django-ish way of doing this would be using the "regroup" template tag:

{% regroup video.actor_video_set.all by actor as video_times %}
{% for actor_times in video_times %}
    <li>{{ actor_times.grouper }}: # this will output the actor's name
    {% for time in actor_times %}
        <li>{{ time }}</li> # this will output the time
    {% endfor %}
    </li>
{% endfor %}

That way you'd avoid having to use more logic than you want in your template. BTW, you can read on the regroup tag here

dguaraglia