Django 查询计数和更新

Django Queries Count and update

我有以下两个模型 ASPBoookings 和 Athlete。 Athlete 模型通过名为 athlete 的外键链接到 ASPBookings 模型。

我最近 queries/subqueries 看到了视图,我一直在尝试使用它们(仍在学习)来提供分配给 ASPBookings table 中每个运动员的所有预订的计数。一旦我获得了信息,我需要运动员模型中的“number_of_asp_sessions”自动更新每个运动员的预订计数。

例如运动员 ID 1,可能有两个预订。运动员 ID 2,可以分配一个预订。 number_of_asp_sessions 然后应该显示每个运动员的这些数字。

希望这是有道理的,感谢您提前提供任何帮助。欣赏一下。

代码如下:

ASPBookings 模型

class ASPBookings(models.Model):
    asp_booking_ref = models.CharField(max_length=10, default=1)
    program_type = models.CharField(max_length=120, default='asp')
    booking_date = models.DateField()
    booking_time = models.CharField(max_length=10, choices=booking_times)
    duration = models.CharField(max_length=10, choices=durations, default='0.5')
    street = models.CharField(max_length=120)
    suburb = models.CharField(max_length=120)
    region = models.CharField(max_length=120, choices=regions, default='Metro')
    post_code = models.CharField(max_length=40)
    organisation_type = models.CharField(max_length=120,choices=organisation_types, default='Government School')
    audience_number = models.CharField(max_length=10)
    presentation_form = models.CharField(max_length=120, choices=presentation_form_options, default='Face to Face')
    contact_name = models.CharField(max_length=80)
    email = models.EmailField()
    phone_number = models.CharField(max_length=120)
    comments = models.TextField()
    status = models.CharField(max_length=80, choices=statuses, default='TBC')
    email_sent = models.BooleanField(default=False)
    athlete = models.ForeignKey(Athlete, default= '1', on_delete=models.CASCADE)

    def __str__(self):
        return self.contact_name
        
    # return URL after the POST has been submitted.
    def get_absolute_url(self):
        return reverse('vistours:success')

运动员模特。

class Athlete(models.Model):
    athlete_ref = models.CharField(max_length=10, default=1)
    athlete_name = models.CharField(max_length=80)
    email = models.EmailField()
    phone_number = models.CharField(max_length=120)
    home = models.CharField(max_length=120)
    education = models.CharField(max_length=120)
    sport = models.CharField(max_length=120, choices=sports, default='1500m Runner')
    notes = models.TextField(default='None')
    gender = models.CharField(max_length=120, choices=genders, default='Not Specified')
    para_athlete = models.BooleanField(blank=True)
    working_with_children = models.BooleanField(blank=True)
    expiry_date = models.DateField(blank=True, null=True)
    available = models.BooleanField(blank=True)
    available_from = models.DateField(blank=True, null=True)
    bfbw = models.BooleanField(blank=True)
    latest_bfbw_session = models.DateField(blank=True, null=True)
    number_bfbw_sessions = models.CharField(blank=True, null=True, max_length=10)
    asp = models.BooleanField(blank=True)
    latest_asp_session = models.DateField(blank=True, null=True)
    number_asp_sessions = models.CharField(blank=True, null=True, max_length=10)
    tours = models.BooleanField(blank=True)
    latest_tours_session = models.DateField(blank=True, null=True)
    number_tours_sessions = models.CharField(blank=True, null=True, max_length=10)

    def __str__(self):
        return self.athlete_name

    # return URL after the POST has been submitted.
    def get_absolute_url(self):
        return reverse('home')

VIEW

def count_bookings(request):

    Athlete.objects.annotate(number_of_asp_sessions=Count('aspbookings')).update(number_asp_sessions=F('number_of_asp_sessions'))
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

我想你需要注释试一次。

ASPBookings.objects.annotate(num_athletes=Count('program_type'))

试试下面的方法:

Athlete.objects.annotate(number_of_asp_sessions=Count('aspbookings')).update(number_asp_sessions=F('number_of_asp_sessions')

这将计算每个运动员的所有 asp 预订,然后根据所有运动员的注释字段一次性更新 number_asp_sessions 字段。

编辑:

我试过了,我得到了:

    FieldError: Aggregate functions are not allowed in this query

看来我无法使用带注释的字段进行更新。现在这应该可以工作:

objs = []
for a in Athlete.objects.annotate(number_of_asp_sessions=Count('aspbookings')):
    a.number_asp_sessions = a.number_of_asp_sessions
    objs.append(a)
Athlete.objects.bulk_update(objs, ['number_asp_sessions'])

编辑:

最终使用了子查询 ;) 这也应该有效:

Athlete.objects.update(
     number_asp_sessions=Subquery(
          Athlete.objects.annotate(number_of_asp_sessions=Count('aspbookings')).filter(pk=OuterRef('pk')).values('number_of_asp_sessions')[:1]
     )
)

您不需要字段 number_asp_sessions。 您正在寻找的是从 Athlete

访问到 ASPBookings 的反向关系

您可以简单地向模型添加一个方法Athlete

class Athlete(models.Model):
    athlete_ref = models.CharField(max_length=10, default=1)
    ...
    ...
    def get_number_of_sessions(self):
        return self.aspbookings_set.all().count()

aspbookings_set是指从classAthlete

的实例来看classASPBookings的外键引用实例