django - 如何绑定另一个表中计算的计数值的表记录

问题描述:

在我的应用程序中,我有一个培训列表。此列表中的一个字段应显示每个培训的预订数量。 为了说明我的意思我准备的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

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

我想从另一个方向的方法: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'只会减慢页面加载的速度,它会在页面加载时计算每个对象的计数值。因此,如果物体的数量和计算量太多,就太慢了。 –