2016-08-02 118 views
2

在我的應用程序中,我有一個培訓列表。此列表中的一個字段應顯示每個培訓的預訂數量。 爲了說明我的意思我準備的SQL查詢:django - 如何綁定另一個表中計算的計數值的表記錄

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 

你能不能給我一些建議如何做到這一點在Django? 我在我的代碼中使用了Booking.objects.all().values('training_id').annotate(booked_amount=Count('training_id')),但結果是所有培訓的所有計數值都顯示在列表上的每個培訓中。應顯示一個適合每次培訓的計數值。

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

所以,如果我得到它的權利,你想**培訓ID **和* *所有預訂組的預訂對象數**,由training_id分組。我對此有正確的理解嗎?還是你想要別的東西? –

+0

在我的培訓列表中,我希望顯示每次培訓的預訂對象的計數(對於每個training_id) – annlii

回答

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

歡迎來到堆棧溢出:-)請看[answer] – JimHawkins

+0

@annlii,這是答案之一。但是,從技術上講,如果在context ['trainings']中有'n'個訓練對象,那麼你需要向你的''n''個數字的'Booking.objects.filter(training_id = each_training.id).count()'查詢數據庫。因此,如果'n'的值上升,您將能夠看到使用** DjangoDebugToolbar **,它爲您的頁面加載花費了太多時間。儘管您爲SQL編寫的等效查詢只是一個查詢,可以爲您返回所需的一切。 –

+0

@AnkushRaghuvanshi感謝您注意到這個問題。現在對我來說沒問題,但後來我可能不得不提高效率。 – annlii

0

我想從另一個方向的方法:each_training.booking_set.count()

而且,我不知道它適合你的數據庫的目標,但如果我明白你在找什麼,你可以設置它是這樣的:

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 

像這樣,值可以直接從模型轉到模板。

我能看到的唯一問題是我認爲它阻止了這些字段成爲查詢集的一部分。例如,Training.objects.filter(counter__gt=0)將不起作用。如果你需要的話,我認爲你仍然必須找到一個機會來保存和更新數據庫中的值,possibly using a signal,這樣每次調用視圖時都不必一次又一次地保存值。

它也像你可以使用一個經理來處理一些您可以在視圖都在做邏輯:

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') 

然後你可以經理添加到您的模型(即一定要保持你的香草經理):

models.py

from .managers import Courses 

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

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

現在,您可以使用纖細的ListView分發所有信息。

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) 

我不熟悉你在模板中做的一些事情,但是一切都應該像現在一樣工作。

或許我的路要走,但我希望它的一些好的精神食糧:)

+0

定義@屬性不會將該屬性的值存儲在數據庫中,因此在它的要求時間。所以在技術上使用'def counter'只會減慢頁面加載的速度,它會在頁面加載時計算每個對象的計數值。因此,如果物體的數量和計算量太多,就太慢了。 –

相關問題