2010-11-21 21 views
0

J'ai une liste d'objets:combiner les données de modèle avec la liste des objets

film_hc = [{'count': 2, 'pk': '33'}, 
      {'count': 1, 'pk': '37'}, 
      {'count': 1, 'pk': '49'}] 

La valeur « pk » est la clé primaire pour un enregistrement dans un modèle. Je voudrais ajouter le champ de nom de cet enregistrement à cette liste d'objets. Pour obtenir un nom, je peux utiliser:

record = Film.objects.get(pk = film_hc[0]['pk']) 
record.name 

En fin de compte, je voudrais avoir quelque chose comme ceci:

film_hc = [{'count': 2, 'pk': '33', 'name': 'name1'}, 
      {'count': 1, 'pk': '37', 'name': 'name2'}, 
      {'count': 1, 'pk': '49', 'name': 'name3'}] 

Question: Quelle est la façon la plus efficace de joindre les données nécessaires à cette liste préexistante?

Je pense que je pourrais utiliser la fonction zip:

film_hc_with_names = zip(????, film_hc) 

Le problème est que je ne suis pas sûr de ce que je remplacerais à la place de ceux ???? pour obtenir l'objet, puis le nom de chaque objet dans la liste. Dois-je utiliser une boucle for à la place? Quelle est l'option la plus préférable?

Répondre

1

Pour éviter de cliquer plusieurs fois sur la base de données, nous vous recommandons d'utiliser la méthode de requête inverse in_bulk. Cela prend une liste d'ID et renvoie un dictionnaire d'ID mappé à l'instance de modèle. Donc, ce que vous devez faire est de parcourir votre liste de dictionnaires d'abord pour extraire les valeurs d'ID, puis faites la requête, puis réexécutez pour obtenir le nom de chaque instance. Même si cela fait deux itérations supplémentaires, il devrait être encore plus rapide que d'exécuter plusieurs requêtes de base de données (même si, comme toujours, vous devez le profiler pour être sûr).

id_list = [film['id'] for film in film_hc] 
objects = Film.objects.only('name').in_bulk(id_list) 
for film in film_hc: 
    film['name'] = objects[film['id']].name 
+0

Je vais certainement trouver une utilisation de in_bulk à un moment donné. Dans ce cas, je ne sais pas s'il est logique d'itérer deux fois. On dirait que nous pourrions le faire en un. –

+0

@Ed, cela dépend de vous bien sûr, mais vous ne devriez pas vous concentrer uniquement sur l'itération comme étant l'inefficacité principale. Frapper plusieurs fois la base de données est beaucoup plus inefficace. Un test rapide exécutant 'ab' pour 100 hits contre mon code vs aaronsterling ci-dessus a montré 0.370ms pour le mien contre 0.542ms pour le sien: donc ma méthode est environ 50% plus efficace. –

+0

hmm. Tu as raison. Testé et cela fonctionne beaucoup plus vite. Merci pour le suivi. –