views:

1382

answers:

4

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,
})
+3  A: 
randomPhotos = [random.choice(album.photos.objects.all()) for album in album.objects.all()]
Dan Lorenc
oooh, list comprehension, nice!
Gabriel Hurley
for album in Album.objects.all()
Lakshman Prasad
Tried this:>>> import random>>> randomPhotos = [random.choice(album.photos.objects.all()) for album in Album.objects.all()]and got this:Traceback (most recent call last): File "<console>", line 1, in ?AttributeError: 'ManyRelatedManager' object has no attribute 'objects'>>>
remove the word objects from album.photos.objects.all()
AlbertoPL
Got it. Thanks!
+5  A: 

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
Gabriel Hurley
Need to do something slightly different in the middle as it's assuming photos all have primary keys in range 0 to total. Can I get a random element from a list of all album.photos?
http://elpenia.wordpress.com/2010/05/11/getting-random-objects-from-a-queryset-in-django/
superjoe30
+1  A: 

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

Rob Golding
+8  A: 

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()]
sixthgear
+1: looks like this is a good way to do it, and if I could i'd give you another +1 for teaching me something about order_by i didn't know! thanks!
TokenMacGuy
+1 for the order_by knowledge as well.
Harold
please see http://buffis.com/2008/01/20/how-to-get-random-rows-from-mysql-using-django/comment-page-1/
chefsmart
Read your blog post chefsmart. What happens in your example if one of the records is deleted, or for some other reason, the set of ids is not a sequential, contiguous set starting with 1?
sixthgear