Multiple For Loops Django

Viewed 71

I have the following two models ASPBoookings and Athlete. The Athlete model is linked to the ASPBookings model by the foreign key named athlete.

I am trying to create a loop that will cycle through all of the bookings in the ASPBooking table and find out which is the most recent booking by each athlete (the table can contain multiple bookings each to the same or different athletes (athlete_id).

Once I have this information (booking_date and athlete_id), I then want to be able to automatically update the "Lastest ASP Session Field" in the Athlete Model.

This is what I have tried so far. I can cycle through the bookings in the ASPBookings table and retrieve and update the "Latest ASP Session Field" using the booking_date and athlete_id, but I cannot do this for multiple different athletes that are within the table. Currently the view just identifies the latest booking and the assigned athlete_id and then updates the field.

Thanks in advance for any help.

Below is the code:

ASPBookings Model

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

Athlete Model

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

# Complete first loop for inital values.
    for date in asp_data:
        if date.booking_date != None:
            first_loop = date.booking_date
            athl_id = date.athlete_id
            break
    # If next value is greater than inital value, replace current values.      
    for date in asp_data:
        if date.booking_date != None:
            if date.booking_date > first_loop:
                first_loop = date.booking_date
                athl_id = date.athlete_id
    

    print(first_loop)
    print(athl_id)

    update_date = Athlete.objects.get(id=athl_id)
    update_date.latest_asp_session = first_loop
    update_date.save()
1 Answers

No need for loops. You can do this for all athletes in just one go using subqueries to leave all the heavy-lifting to your database:

from django.db.models import F, OuterRef, Subquery

bookings = ASPBookings.objects.filter(
    athlete=OuterRef('pk')
).order_by('-booking_date')

Athlete.objects.annotate(
    latest_asp_booking_date=Subquery(
        bookings.values('booking_date')[:1]
    )
).update(
    latest_asp_session=F('latest_asp_booking_date')
)
Related