Perform subqueries for each day in range

Viewed 113

I building a 'airbnb clone' app on Django. The app has a flexible price system. Each landlord-user can save arbitrary number of prices which differ by priority and date range.
Here is how it looks like (most of the fields skipped for the sake of simplicity):

class PriceBlock(models.Model):
    price = models.DecimalField()
    priority = models.CharField(choices=PRIORITY_CHOICES)
    start_date = models.DateField()
    end_date = models.DateField()

class Flat(models.Model):
    prices = models.ManyToManyField(PriceBlock, related_name='flats')

For example User created 3 PriceBlock instances with date values in some random month.
enter image description here

p1 - has priority 1, price 100$ and dates from 1 to 3
p2 - has priority 2, price 200$ and dates from 2 to 5
p3 - has priority 3, price 300$ and dates from 4 to 6
To calculate price for flat from 1 to 6 days on this month we need to calculate price of PriceBlock with higher priority on each day.
The problem is - I need calculate price for each flat in the ListView of all flats.
Here's how I do it:

class FlatQueryset(models.QuerySet):
    ...
    def with_block_full_price(self, start, end):
        days = get_days(start, end) # function returns list of days nums
        prices = {}

        for num, day in enumerate(days):
            prices[f'price_{num}'] = Subquery(
                PriceBlock.objects.filter(flats=OuterRef('pk'))
                    .filter(start_date__lte=day, end_date__gte=day)
                    .order_by('-priority')
                    .values('price')[:1],
                output_field=models.IntegerField(null=True))
        return self.annotate(**prices).annotate(full_sum=sum([F(key) for key in prices.keys()]))

I create subqueries in loop, each subquery returns price value most prioritize PriceBlock or null, in case of null I don't show the Flat. Then I add all price values to full_sum value.

As far as I know I can't do queries like this in raw SQL without repeating all subqueries for each date. I also have a task on calculating rating of each flat and I did it in similar way.
I curios maybe there is much better solution on task like this, because my solution looks messy.

0 Answers
Related