Search code examples
pythondjangomodelbusiness-logic

Django - Stuck On Creating a Pricing System


I am making a "booking airbnb" website.

On my apartment detail page, I have a JQuery UI Date Picker calendar which the user uses to put in start and end dates of the reservation.

Once that is done and the user submits the form I want to refresh the whole site, and when refreshed display the dates that the user picked earlier, as long with price per day and total price.

In my models I have created:

models.py:



class Apartment(models.Model):
    title = models.CharField(max_length=200)
    address = models.CharField(max_length=200)
    city = models.CharField(max_length=100)
    state = models.CharField(max_length=100)
    zipcode = models.CharField(max_length=20)
    description = models.TextField(blank=True)
    apartment_price = models.IntegerField()
    bedrooms = models.IntegerField()
    bathrooms = models.DecimalField(max_digits=2, decimal_places=1)
    garage = models.IntegerField(default=0)
    size = models.IntegerField()
    photo_main = models.ImageField(upload_to='photos/%Y/%m/%d/')
    list_date = models.DateTimeField(default=datetime.now, blank=True)

    def __str__(self):
        return self.title

class ApartmentImages(models.Model):
    apartment = models.ForeignKey(Apartment, on_delete="models.CASCADE", related_name="image")
    image = models.ImageField("image")

    def __str__(self):
        return self.image.url


class ApartmentPrices(models.Model):
    apartment = models.ForeignKey(Apartment, on_delete="models.CASCADE", related_name="price")
    price_start_date = models.DateField(blank=True, null=True)
    price_end_date = models.DateField(blank=True, null=True)
    price = models.IntegerField()

    def __str__(self):
        return self.apartment.title

class Reservation(models.Model):
    apartment = models.ForeignKey(Apartment, related_name='reservations',
                                  on_delete=models.CASCADE, blank=True, null=True)
    start_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)
    name = models.CharField(default="", max_length=200)

    def __str__(self):
        return self.name

this is what I have in my view so far. I have tried many different things, but I'm stuck on the logic on how is this supposed to work.

here is my view :


def apartment_view(request, apartment_id):

    reservation = Reservation.objects.filter(apartment__pk=apartment_id)
    apartment = get_object_or_404(Apartment, pk=apartment_id)
    prices = ApartmentPrices.objects.filter(apartment__pk=apartment_id)
    context = {}
    context['apartment'] = apartment
    context['prices'] = prices

    # svi datumi za cijene
    price_dates = []
    for start, end, price in prices.values_list('price_start_date', 'price_end_date', 'price'):
        while start <= end:
            price_dates.append(start.strftime('%-d-%m-%Y'))
            price_dates.append(price)
            start += datetime.timedelta(days=1)


    unavailable = []
    for start, end in apartment.reservations.values_list('start_date', 'end_date'):
        while start <= end:
            unavailable.append(start.strftime('%-d-%m-%Y'))
            start += datetime.timedelta(days=1)
    form = ReservationForm()
    context['unavailable_dates'] = json.dumps(unavailable)
    context['form'] = form

    if request.method == 'GET':
        form = ReservationForm()

    elif request.method == 'POST':
        form = ReservationForm(request.POST)
        if form.is_valid():
            reservation = form.save(commit=False)
            reservation.apartment = apartment
            reservation.save()
            form.save()
            return render(request, "booking/apartment.html", context)


    return render(request, 'booking/apartment.html', context)

So could anyone help me figure out what would be the best way to compare user picked dates to the price dates in the DB and get the price?

Thanks so much, been stuck on this for a while now.


Solution

  • You could give Appartment a method to fetch the price where a given date object is is between start and end date. (untested)

    ...
    from django.db.models import Q
    
    
    class Apartment(models.Model):
        ...
        def price_by_date(self, date_obj):
            """returns the first price with date_obj is between start and end date
    
            Args:
                date_obj(datetime.date): the date of the price you want
    
            Returns:
                ApartmentPrices: first valid price found
            """
            # self.price is a back reference to all prices with self as apartment
            # you named it by giving related_name="price" in ApartmentPrices.apartment
            return self.price.filter(
                Q(price_start_date__lte=date_obj) & Q(price_end_date__gte=date_obj)
            ).first()
        ...
    

    In the view you should be able to do:

    ...
    def apartment_view(request, apartment_id):
    
        reservation = Reservation.objects.filter(apartment__pk=apartment_id)
        apartment = get_object_or_404(Apartment, pk=apartment_id)
        date_price = apartment.price_by_date(datetime.date(2019, 10,18))
        # date_price.price would be the integer
        ...
    

    Further information:

    Q - queries are used to combine the two queries (start + end) to one query.