Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Select a random photo from each Album

Am trying to get a random photo from each album from the data created by syncr. The model (abbreviated) looks like this:


class Album(models.Model):
    title = models.CharField(max_length=200)
    photos = models.ManyToManyField('Photo')

class Photo(models.Model):
    title = models.CharField(max_length=200)

I've tried lots of different approaches with no success. Is this another easy one?

Take 2: Final code:

def galleries(request, template_name='galleries.html'):

albums = Album.objects.select_related().all()
album_list = []
for album in albums:
   album_list.append({'title':album.title, 'id':album.id, 'photo':album.random_photo()})

return render_to_response(template_name, {
     "album_list": album_list,
})
like image 535
PhoebeB Avatar asked Jul 16 '09 17:07

PhoebeB


4 Answers

You can get a single random object from any Queryset using the order_by method with a question mark as an argument. This may be better than calling Photo.objects.all() because it will only return one photo object per query from the database, rather than the whole set and then using python to filter the list.

For instance, this query will return a single random photo:

Photo.objects.order_by('?')[:1]

The following is not optimal, because it needs 1 query for each album, but it would work:

photos = []
for a in Album.objects.all():
    photo = a.photos.order_by('?')[:1]
    photos.append(photo)

Edit: Changed the [0] index to [:1] because the former will raise an IndexError if the albumn contains no photos.

Alternatively, in list comprehension syntax:

photos = [a.photos.order_by('?')[:1] for a in Album.objects.all()]
like image 83
sixthgear Avatar answered Oct 19 '22 22:10

sixthgear


I haven't tested the code, but this is the right idea, and the select_related should help you from incurring tooooo many db queries...

from models import Album, Photo
import random

def get_random():
    albums = Album.objects.select_related().all()
    randpics = []
    for album in albums:
        total = album.photos.count()
        photo = album.photos.get(pk=random.randrange(0,total))
        randpics.append(photo)
    return randpics
like image 39
Gabriel Hurley Avatar answered Oct 19 '22 23:10

Gabriel Hurley


randomPhotos = [random.choice(album.photos.objects.all()) for album in album.objects.all()]
like image 4
Dan Lorenc Avatar answered Oct 19 '22 23:10

Dan Lorenc


If you make a custom method in your Album model, that looks something like this:

def random_photo(self):
    import random
    return random.choice(self.photos.all())

That will return a random photo from the current Album instance i.e.

albumObj.random_photo()

Note: Untested code

like image 3
Rob Golding Avatar answered Oct 19 '22 23:10

Rob Golding