Ordering in the admin

10 views
Skip to first unread message

Wendy

unread,
Aug 13, 2010, 12:52:13 PM8/13/10
to Django users
I have a many to many field, with the horizontal available and chosen
boxes in the admin. I wanted to see if there's any way that an admin
can select the order that the chosen objects show up, and have it be
saved and display that way. Right now, they're not ordered, but seem
to show up based on when the object was created. So I'm choosing
filmmakers for a film, and the only way I can change the order is to
destroy the filmmaker objects, then recreate and add them in a
different order, something that obviously wouldn't work in the real
world. Is there any way to save the order in the chosen box in the
admin?

Thanks,
Wendy

Nick Serra

unread,
Aug 13, 2010, 1:03:42 PM8/13/10
to Django users
You can go two directions with this. First, you could use a
intermediate model for the many to many join, which would allow you to
specify extra field on the join, in this case the order. Read up on
this here:
http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

The problem with solution one is that the many to many won't be
editable on that page anymore.

Solution two would be to scrap the manytomany and use inline models
instead. You would make an intermediate model, say FilmmakerItem,
which would foreign key to the model you want to join to, and a
foreign key to the filmmaker, and would have a field for order. This
would be editable in the admin under the same page.

Read about inline here:
http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects

Wendy

unread,
Aug 16, 2010, 3:24:09 PM8/16/10
to Django users
Thanks Nick,
I tried the first solution first.
You're right, the many to manys aren't editable on that page, but the
problem is, I'm not seeing another admin page for the new join model:

class FilmmakerPosition(models.Model):
filmmaker = models.ForeignKey(Filmmaker)
film = models.ForeignKey(Film)
position = models.IntegerField()
----------------------------------------------------
(it is in the db)
so there's no way I can assign filmmakers to a film in the admin.
In the Film class it specifies:
--------------------
filmmakers = models.ManyToManyField(Filmmaker,
through='FilmmakerPosition')
--------------------

Am I missing something?

I was slightly more intimidated by the inline example, as I'm not sure
I want to scrap the many to many relationship. (there are lots of
films that have multiple filmmakers and vice versa, and I'd like to be
able to list them on both ends) I'm still trying to wrap my head
around how I could do that with this example.

If anyone has anything else to add that would help me understand it
better, I'd really appreciate it.

Thanks,
Wendy


On Aug 13, 10:03 am, Nick Serra <nickse...@gmail.com> wrote:
> You can go two directions with this. First, you could use a
> intermediate model for the many to many join, which would allow you to
> specify extra field on the join, in this case the order. Read up on
> this here:http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-o...
>
> The problem with solution one is that the many to many won't be
> editable on that page anymore.
>
> Solution two would be to scrap the manytomany and use inline models
> instead. You would make an intermediate model, say FilmmakerItem,
> which would foreign key to the model you want to join to, and a
> foreign key to the filmmaker, and would have a field for order. This
> would be editable in the admin under the same page.
>
> Read about inline here:http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodelad...

Nick Serra

unread,
Aug 16, 2010, 3:28:37 PM8/16/10
to Django users
The inline solution is the pretty way to do it. If you just want the
join to show up in the admin, then simply register the join model in
the admin like any other model. In your admin,py include
FilmmakerPosition and then do admin.site.register(FilmmakerPosition)

Wendy

unread,
Aug 16, 2010, 3:45:44 PM8/16/10
to Django users
Thanks, Nick, I just figured that out, doh! So I got the first
example going, I guess I'll try the inline solution as well, if it's
the pretty way to do it... It'll be good for me to actually see what
they both do.
W

Wendy

unread,
Aug 16, 2010, 5:08:04 PM8/16/10
to Django users
OK, I have the inline solution working in the admin, I can see why
it's prettier!
Now I'm trying to figure out how to refer to these filmmakers in my
film list template, as there is no longer a film.filmmakers object...
So when I look in mysql, films_filmmakerposition has an id, a
filmmaker id, a film id and a position.
My Filmmaker Object has a first name and last name.
I'm not sure where to start on this one, any help would be greatly
appreciated.
Thanks,
Wendy

Nick Serra

unread,
Aug 16, 2010, 5:13:20 PM8/16/10
to Django users
Can you list your models.py for me? What exactly do you want to show
in your template? I'm guessing some sort of WHERE clause, like all
filmmakers for a film or something.

Wendy

unread,
Aug 16, 2010, 6:12:21 PM8/16/10
to Django users
Sure, it's pretty big, here are the relevant fields pulled out:
class Filmmaker (models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)

def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)


class Film(models.Model):
title = models.CharField(max_length=180)
slug = models.SlugField(unique=True)
#filmmakers = models.ManyToManyField(Filmmaker)
topics = models.ManyToManyField(Topic, blank=True)

def __unicode__(self):
return self.title

class FilmmakerPosition(models.Model):
filmmaker = models.ForeignKey(Filmmaker)
film = models.ForeignKey(Film)
position = models.IntegerField()

--------------------------

In admin.py:

class FilmmakerPositionInline(admin.TabularInline):
model = FilmmakerPosition


class FilmAdmin(admin.ModelAdmin):
inlines = [
FilmmakerPositionInline,
]
... (there's more)

---------------------------------------

Anyway, this was what I was using in my template when filmmakers was a
many to many relationship with film (commented out in the model
stuff):
by {% with film.filmmakers.all as filmmakers %}
{% for filmmaker in filmmakers %}
{% if filmmakers|length > 2 and not forloop.first %}, {% endif
%}
{% if forloop.last and not forloop.first %}and {% endif %}
{{filmmaker.first_name }} {{filmmaker.last_name}}
{% endfor %}
{% endwith %}

Thanks,
Wendy

Nick Serra

unread,
Aug 16, 2010, 7:00:18 PM8/16/10
to Django users
In your view do:

filmmakeritems =
FilmmakerPosition.objects.filter(film=the_film).order_by('position')

Pass that into your template. Then in your template do:

{% for item in filmmakeritems %}
Name: {{ item.filmmaker.first_name }}
{% endfor %}


Etc...

Wendy

unread,
Aug 16, 2010, 7:46:51 PM8/16/10
to Django users
It doesn't know what the_film is:
name 'the_film' is not defined

if I put quotes around 'the_film', it's expecting an integer:
invalid literal for int() with base 10: 'the_film'

I think that what's happening, it's trying to match the id.

I'm going to read about filtering a little more, feels like it's
close...
(I also tried to put film_id in the parens after filter and got a "too
many values" error.)
So much to learn, thanks for all your help,
Wendy

Nick Serra

unread,
Aug 17, 2010, 12:55:05 AM8/17/10
to Django users
The_film was just sudo code. I was assuming you wanted to show
filmmakers based on a movie id. I would recommend going through the
django tutorials if you haven't, they go over all of the queries and
how the general layout goes when doing stuff like this.

Wendy

unread,
Aug 17, 2010, 12:57:23 PM8/17/10
to Django users
Thanks Nick,
I guess I'll be passing that value, that makes sense.
I'm using a generic view to write the list page, I'll read up more on
the queries, thanks for all your help,
Wendy
Reply all
Reply to author
Forward
0 new messages