2010-08-17 2 views
33
myqueryset = Content.objects.filter(random 100) 

Répondre

61
Content.objects.all().order_by('?')[:100] 

Voir la order_by docs. Sachez également que cette approche ne s'adapte pas bien (en fait, elle évolue vraiment, très mal). Voir this SO answer pour une meilleure façon de gérer la sélection aléatoire lorsque vous avez de grandes quantités de données.

+5

Et le tout() est redondant, mais je ne m'en souviens jamais. – Tom

+0

C'est génial! Par le débogage, j'ai remarqué qu'il génère même une bonne requête, en saisissant seulement 20 éléments, en utilisant 1 requête, en utilisant ORDER BY RAND() pour random. Bon dieu, c'est fantastique. –

9

Si vous allez le faire plus d'une fois, vous devez le concevoir dans votre base de données.

Si vous le faites une fois, vous pouvez vous permettre de payer la pénalité lourde. Cela vous donne exactement 100 avec de très bonnes propriétés aléatoires. Cependant, il utilise beaucoup de mémoire.

pool= list(Content.objects.all()) 
random.shuffle(pool) 
object_list = pool[:100] 

Voici un autre algorithme qui est également un peu lent car il peut rechercher toute la table. Il n'utilise pas très bien la mémoire du tout et il ne peut pas obtenir exactement 100.

total_count= Content.objects.count() 
fraction = 100./total_count 
object_list = [ c for c in Content.objects.all() if random.random() < fraction ] 

Si vous voulez faire plus d'une fois, vous devez ajouter un attribut au contenu pour permettre un filtrage efficace pour « aléatoire " valeurs. Par exemple, vous pourriez le faire.

class Content(models.Model): 
    ... etc. ... 
    def subset(self): 
     return self.id % 32768 

Cela va partitionner vos données en 32768 sous-ensembles distincts. Chaque sous-ensemble est 1/32768ème de vos données. Pour obtenir 100 éléments aléatoires, vous avez besoin de 100 * 32768/total_count sous-ensembles de vos données.

total_count = Content.objects.count() 
no_of_subsets= 100*32768/total_count 
object_list = Content.objects.filter(subset__lte=no_of_subsets) 

Ceci est rapide et il est reproductible. Les sous-ensembles sont «arbitraires» et non techniquement «aléatoires».

+0

Bon point pour la performance –

+0

J'aime votre dernière approche même si je ne pense pas que vous pouvez filtrer sur les propriétés. Vous devez ajouter la colonne de sous-ensemble dans le modèle lui-même et définir sa valeur sur Enregistrer comme ceci: http://ifacethoughts.net/2009/07/14/calculated-fields-in-django/ – jesal

+0

Ajouter un sous-ensemble comme méthode au modèle de contenu n'est pas suffisant pour filtrer, comme suggéré dans votre dernier extrait. –

1

je fais:

import random  
object_list = list(Content.objects.filter(foo=bar).values()[:100]) 
random.shuffle(object_list) 

Runs seule requête MySQL simple simple et est bon sur la performance.

+1

Cela ne retourne pas les enregistrements aléatoires de la base de données. Il choisit le premier disque de centaine et les mélange. Les enregistrements 101 et suivants n'ont aucune chance d'être sélectionnés. – Blair

+0

Je voulais suggérer l'utilisation de la fonction shuffle sur order_by ('?') Qui a de sérieux problèmes de performance: http://stackoverflow.com/a/6405601/232649 Pour shuffler tous les enregistrements: shuffle (list (Content.objects .all())) [: 100] – Pratyush

Questions connexes