2009-11-25 5 views
2

J'ai de gros ensembles de données que je suis en boucle pour afficher un tableau de données. Le problème, c'est que le looping prend beaucoup de temps, ce qui est correct pour le moment car c'est un outil interne mais je voudrais l'améliorer.Une meilleure façon de faire défiler plusieurs listes dans un modèle django

Le modèle:

class Metric_Data(models.Model): 
    metric = models.ForeignKey(Metric) 
    count = models.IntegerField() 
    start_date = models.DateField() 

Je suis affichant une table où la première colonne est la date alors chaque colonne suivante est une mesure indiquant le nombre pour cette date. Comme si:

Dates Metric Metric Metric ... 
10/11  10  11  12 
11/11  22 100 1000 
...  ... ... ... 

J'ai essayé en boucle sur les données de la vue et la création de la table sur les listes et la passer à modèle pour le rendu, mais avec plusieurs mesures et des milliers de points de données par mesure cela était assez lent. Je suis depuis passé à une étiquette de modèle:

def getIndex(parser, token): 
    try: 
    tag_name, a_list, index = token.split_contents() 
    except ValueError: 
    raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0] 
    return GetIndexNode(a_list, index) 

class GetIndexNode(template.Node): 
    def __init__(self, a_list, index): 
    self.the_list = template.Variable(a_list) 
    self.index = template.Variable(index) 

    def render(self, context): 
    try: 
     the_list = self.the_list.resolve(context) 
     i = self.index.resolve(context) 
     return the_list[i] 
    except template.VariableDoesNotExist: 
     return '' 

Ce qui est encore assez lent, ce qui ne pouvait, car il est la première fois en train d'écrire une étiquette de modèle et je l'ai fait quelque chose de mal.

EDIT: J'aller chercher les données dans la vue comme ceci:

def show_all(request): 
    metrics = Metric.objects.all() 
    dates = Metric_Data.objects.all().values_list('start_date',flat=True).distinct().order_by('start_date') 

    data = [] 

    for metric in metrics: 
    data.append(Metric_Data.objects.filter(metric=metric).order_by('start_date').values_list('count', flat=True)) 

    return render_to_response('metric/show_all.html', {'dates': dates, 
                'metrics': metrics, 
                'data': data}) 

Edit: Et le modèle

<table id="theTable" class="paginate-5"> 
<thead> 
<tr> 
<th>Dates</th> 
    {% for metric in metrics %} 
     <th>{{ metric.name }}</th> 
    {% endfor %} 
</tr> 
</thead> 
<tbody> 
{% for date in dates %} 
    <tr> 
    <td>{{date}}</td> 
    {% for metric in data %} 
     <td>{% get_index metric forloop.parentloop.counter0 %}</td> 
    {% endfor %} 
    </tr> 
{% endfor %} 
</tbody> 

Je pense le meilleur endroit pour résoudre ce problème pourrait être dans le modèle, mais je ne suis pas sûr de savoir comment s'y prendre. Créer une table pour les dates peut-être et faire la requête sur cette table?

Des idées très appréciées merci!

+0

Comment chercher-vous vos données de votre base de données? – Kugel

+0

Mis à jour avec vue :) –

+0

S'il vous plaît également montrer le modèle qui appelle ce tag. –

Répondre

1

Je pense que vous êtes en train de mal regrouper vos données, de sorte que vous finissez par faire plusieurs boucles sur les mêmes éléments, ce qui engendre une très faible complexité. Essayez de structurer vos données de très près à la manière dont elles seront utilisées dans le modèle.

Par exemple:

def metric_count_on (metric, date): 
    return Metric_Data.objects.filter(metric=metric,start_date=date).values_list('count',flat=True) 
def show_all(request): 
    metrics = Metric.objects.all() 
    dates = Metric_Data.objects.all().values_list('start_date',flat=True).distinct().order_by('start_date') 
    # generate full report. now, template only has to loop. 
    data = [{'date':date, 'metrics':metric_count_on(date, metric)} 
     for (date,metric) in itertools.product(dates,metrics)] 
    # ... 

Ensuite, dans le modèle, vous pouvez fondamentalement juste boucle comme:

{% for row in data %} 
    <tr> 
    <td>{{ row.date }}</td> 
    {% for count in row.metrics %} 
     <td>{{ count }}</td> 
    {% endfor %} 
    </tr> 
{% endfor %} 
+0

Remarque: cela produira beaucoup plus de requêtes de base de données que dans votre code (une par combinaison 'metric' /' date'). Vous voudrez peut-être récupérer toutes les données et calculer vous-même le regroupement logique s'il y a trop de frais généraux. –

0

Si vous trouvez que votre vue est lente, le problème est souvent dans la base de données. Êtes-vous sûr de savoir quelles requêtes vont à la base de données? Il est possible que vous puissiez faire un petit changement qui réduirait considérablement le trafic db.

+0

Mise à jour avec vue :) –

0

J'ai trouvé ce blog qui semble faire allusion à des problèmes similaires.

http://www.xorad.com/blog/?p=1497

En utilisant « | sécurité » sur toutes mes variables couper mon temps de charge dans la moitié qui est au moins quelque chose ...

affichage au cas où quelqu'un d'autre bute sur ce problème.

+1

Assurez-vous de bien comprendre à quoi sert «sûr» avant de l'utiliser sans discernement. –

Questions connexes