2016-08-02 3 views
2

In meiner Anwendung habe ich eine Liste von Schulungen. Ein Feld in dieser Liste sollte die Anzahl der Buchungen für jedes Training anzeigen. Um zu zeigen, was ich meine, ich SQL-Abfrage vorbereitet:django - wie man Datensätze der Tabelle mit berechneten Zählwerten von einer anderen Tabelle bindet

SELECT * 
FROM club_training a 
LEFT JOIN 
(SELECT training_id, count(*) 
FROM club_booking 
group by training_id) b 
ON a.id = b.training_id 

Können Sie mir einen Rat geben, wie es in django zu tun? Ich habe Booking.objects.all().values('training_id').annotate(booked_amount=Count('training_id')) in meinem Code verwendet, aber das Ergebnis ist, dass alle Zählwerte für alle Trainings für jedes Training auf der Liste angezeigt werden. Es sollte ein Zählwert angezeigt werden, der für jedes Training geeignet ist.

enter image description here

views.py

class HomePageView(TemplateView): 
    """Home Page with list of trainings""" 
    template_name = 'club/training_list.html' 


    def get_context_data(self, **kwargs): 
     now = datetime.datetime.now() 
     context = super(HomePageView, self).get_context_data(**kwargs) 
     context['trainings'] = Training.objects.filter(state="A", training_date__gte=now).order_by('training_date', 'start_time') 
     for each_training in context['trainings']:  
      each_training.diff = each_training.availability - each_training.counter 
      each_training.counter = Booking.objects.all().values('training_id').annotate(booked_amount=Count('training_id')) 
     return context 

models.py

class Training(models.Model): 
    """Class for plan training""" 
    STATE = (
     ('A', 'Active'), 
     ('I', 'Inactive'), 
    ) 
    name = models.ForeignKey('TrnDesc') 
    instructor = models.ForeignKey('Instructor') 
    start_time = models.TimeField(blank=True) 
    end_time = models.TimeField(default='00:00:00') 
    availability = models.PositiveIntegerField(default=15) 
    state = models.CharField(max_length=1, choices=STATE, default='A') 
    training_date = models.DateField(default=date.today) 
    counter = models.PositiveIntegerField(default=0) 
    def __str__(self): 
     return self.name.name 

class Booking(models.Model): 
    """Data of people which book fitness classes""" 
    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50) 
    email = models.CharField(max_length=50) 
    phone = models.CharField(max_length=10) 
    training = models.ForeignKey('Training') 
    def __str__(self): 
     return self.training.name.name 

training_list.html

{% extends 'club/base.html' %} 

{% block content %} 

     <ul class="nav nav-pills"> 
      <li role="presentation" class="active"><a href="#">Fitness Classes</a></li> 
      <li role="presentation"><a href="#">Join Us</a></li> 
      <li role="presentation"><a href="#">Contact Us</a></li> 
     </ul> 
     <br></br> 
    {% regroup trainings by training_date as date_list %} 
    {% for date in date_list %} 
     <div class="panel panel-default"> 


      <div class="panel-heading">{{date.grouper|date:"l, d F o"}}</div> 


      <table class="table"> 
       <tr> 
        <th style="width: 20%">Training name</th> 
        <th style="width: 30%">Training description</th> 
        <th style="width: 10%">Instructor</th> 
        <th style="width: 10%">Start time</th> 
        <th style="width: 10%">End time</th> 
        <th style="width: 10%">Left</th> 
        <th style="width: 10%">Test_counter</th> 
        <th style="width: 10%">Actions</th> 
       </tr> 


       {% for training in date.list %} 

       <tr> 
        <td>{{training.name}}</td> 
        <td>{{training.name.desc}}</td> 
        <td>{{training.instructor}}</td> 
        <td>{{training.start_time|time:"H:i"}}</td> 
        <td>{{training.end_time|time:"H:i"}}</td> 
        <td>{{training.diff}}</td> 
        <td>{{training.counter}}</td> 
        <td><a href="{% url 'book' training_id=training.pk%}"><button type="button" class="btn btn-primary">Book</button></a></td> 
       </tr> 

       {% endfor %}  
      </table> 
     </div> 
    {% endfor %} 

{% endblock %} 
+0

Also, wenn ich es richtig hinzubekommen, Sie ** Ausbildung ID ** und die * erhalten möchten * Anzahl der Buchungsobjekte ** aller Buchungsgruppen, gruppiert nach Trainings-ID. Habe ich es richtig verstanden oder möchtest du etwas anderes? –

+0

In meiner Trainingsliste möchte ich die Anzahl der Buchungsobjekte für jedes Training anzeigen (für jede Trainings-ID) – annlii

Antwort

1
for each_training in context['trainings']:  
     each_training.diff = each_training.availability - each_training.counter 
     each_training.counter = Booking.objects.filter(training_id=each_training.id).count() # just modify this line 
    return context 
+0

Willkommen zum Stack-Überlauf :-) Bitte schauen Sie auf [antworten] – JimHawkins

+0

@annlii, das ist eine der Antworten. Aber technisch gesehen, wenn es 'n' Trainingsobjekte im Kontext ['trainings']' 'gibt, machen Sie' n' Anzahl von 'Booking.objects.filter (training_id = each_training.id) .count()' Anfragen an Ihre Datenbank. Wenn also der Wert von "n" ansteigt, können Sie sehen, dass Sie mit ** DjangoDebugToolbar ** feststellen, dass die Ladezeit für Ihre Seite zu hoch ist. Während die äquivalente Abfrage, die Sie für SQL geschrieben haben, nur eine Abfrage war, die Ihnen alles zurückgibt, was Sie wollten. –

+0

@AnkushRaghuanshi danke, dass du dieses Problem bemerkt hast. Für jetzt ist es in Ordnung für mich, aber später werde ich wahrscheinlich etwas effizienter arbeiten müssen. – annlii

0

ich aus der anderen Richtung nähern würde: 0.123.

Auch ich bin nicht sicher, dass es Ihre Datenbank Ziele passt, aber wenn ich verstehe, was Sie suchen, können Sie es einstellen wie auf den Punkt:

models.py

class Training(models.Model): 
    ... 
    <fields> 
    ... 
    def __str__(self): 
     return self.name.name 

    @property 
    def counter(self): 
     return self.booking_set.count() 

    @property 
    def diff(self): 
     return self.availability - self.counter 

So können die Werte direkt vom Modell zur Vorlage gehen.

Das einzige Problem, das ich damit sehen kann, ist, dass ich denke, dass diese Felder davon abgehalten werden, Teil eines Abfrage-Sets zu sein. Zum Beispiel funktioniert Training.objects.filter(counter__gt=0) nicht. Wenn Sie das brauchen, müssen Sie nach wie vor eine Möglichkeit finden, den Wert in der Datenbank possibly using a signal zu speichern und zu aktualisieren. Auf diese Weise müssen Sie den Wert nicht jedes Mal erneut speichern, wenn die Ansicht aufgerufen wird.

Es sieht auch wie Sie einen Manager nutzen könnten einige der Logik behandeln Sie in der Ansicht zu tun:

managers.py

from django.db.models import Manager 

class Active(Manager): 

    def by_date(self, date) 
     Training.objects.filter(state="A", training_date__gte=date).order_by('training_date', 'start_time') 

Dann können Sie den Manager legen zum Modell (wobei Sie Ihre Vanille-Manager zu erhalten):

models.py

from .managers import Courses 

class Training(models.Model): 
    ... 
    <fields> 
    objects = models.Manager() 
    active = Active() 
    ... 

    def __str__(self): 
     return self.name.name 

Und jetzt können Sie alle Informationen mit einem schlanken ListView verteilen.

from django.views.generic import ListView 

class HomePageView(ListView): 
    """Home Page with list of trainings""" 
    template_name = 'club/training_list.html' 
    context_object_name = "trainings" 

    def get_queryset(self): 
     now = datetime.datetime.now() 
     return Trainings.active.by_date(now) 

Ich bin nicht mit einigen der Dinge vertraut Sie sind in der Vorlage zu tun, aber alles sollte die gleiche Art und Weise arbeiten, um es jetzt der Fall ist.

Oder vielleicht bin ich weg, aber hoffentlich seine etwas Gutes zu denken :)

+0

Das Definieren einer '@ Eigenschaft' speichert den Wert dieser Eigenschaft nicht in der Datenbank und wird daher ** berechnet Zeitpunkt seiner Anforderung. Die Verwendung von 'Def Counter' wird also nur die Seitenbelastung verlangsamen, wenn der Zählwert für jedes Objekt zum Zeitpunkt des Seitenladens berechnet wird. Daher ist es zu langsam, wenn die Anzahl der Objekte und damit die Berechnungen zu groß sind. –