views:

121

answers:

2

I have a query that gets me 32 avatar images from my avatar application:

newUserAv = Avatar.objects.filter(valid=True)[:32]

I'd like to combine this with a query to django's Auth user model, so I can get the last the last 32 people, who have avatar images, sorted by the date joined.

What is the best way to chain these two together?

The avatar application was a reusable app, and its model is:

image = models.ImageField(upload_to="avatars/%Y/%b/%d", storage=storage)
user = models.ForeignKey(User)
date = models.DateTimeField(auto_now_add=True)
valid = models.BooleanField()

Note that the date field, is the date the avatar is updated, so not suitable for my purporse

+1  A: 

It's not possible to combine queries on two different base models. Django won't let you do this (it'll throw an error telling you exactly that).

However, if you have a foreignkey from one model to the other, then adding select_related() to your query will fetch the related objects into memory in a single DB query so that you can access them without going back to the DB.

Gabriel Hurley
Hi Gabriel,I'm not sure I complete understand, so how for example would I query my user model (would I query all users / as if I limited it to the last 32 some might not have an avatar object) - and then pass it on - doing a query for all users by the date joined date seems a bit inefficient?
Tristan
+2  A: 

Either you put a field in your own User class (you might have to subclass User or compose with django.contrib.auth.models.User) that indicates that the User has an avatar. Than you can make your query easily.

Or do something like that:

from django.utils.itercompat import groupby
avatars = Avatar.objects.select_related("user").filter(valid=True).order_by("-user__date_joined")[:32]
grouped_users = groupby(avatars, lambda x: x.user)
user_list = []
for user, avatar_list in grouped_users:
    user.avatar = list(avatar_list)[0]
    user_list.append(user)
# user_list is now what you asked for in the first_place: 
# a list of users with their avatars

This assumes that one user has one and only one avatar. Your model allows for more than one avatar per user so you have to watch out not to store more than one.

Explanation of Code Snippet: The avatars of the most 32 recent joined users are requested together with the related user, so there doesn't have to be a database query for any of them in the upcoming code. The list of avatars is then grouped with the user as a key. The list gets all items from the generator avatar_list and the first item (there should only be one) is assigned to user.avatar

Note that this is not necessary, you could always do something like:

for avatar in avatars:
    user = avatar.user

But it might feel more naturally to access the avatars by user.avatar.

stefanw
Stefanw - this looks really good I'm going to try it out, is there any chance you could add some comments to your code so I can better understand what its doing?
Tristan
This works perfectly (just tested it), but I'd love to understand the code better
Tristan
I've added a bit of explanation.
stefanw