Reputation: 71
I have a CarRent
model that is a ForeignKey to the Car
model. On the Car
detailView page i have a button for drivers to place a Rent which will result in adding a row to the CarRent Table. The rent isn’t active yet until the Car owner approves the rent request. The problem now is that a driver could click the rent button multiple times thereby resulting in many duplicate rows in the CarRent
model and also multiple redundant car rent request to the car owner. I am looking for a way to hide the “Place A Rent” form if the current user (driver) has already requested for a particular car and rent_approval is not True.
Thanks. Any help will be greatly appreciated.
models.py
class Car(models.Model):
car_owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='car_owner', on_delete=models.CASCADE)
car_model = models.CharField(max_length=20, blank=True, null=True)
rented = models.BooleanField(default=False)
class CarRent(models.Model):
car = models.ForeignKey(Car, related_name='rented_car', on_delete=models.CASCADE)
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='driver_renting', on_delete=models.CASCADE)
rent_approval = models.BooleanField(null=True)
active_rent = models.BooleanField(default=False, null=True)
views.py
class CarView(LoginRequiredMixin, UserPassesTestMixin, FormMixin, DetailView):
model = Car
form_class = RentForm
def get_success_url(self):
return reverse('app:car-detail', kwargs={'pk': self.object.pk})
def post(self, request, *args, **kwargs):
form = self.get_form()
self.object = self.get_object()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form, *args, **kwargs):
form.instance.car_id = self.kwargs['pk']
form.instance.driver = self.request.user
form.save()
messages.success(self.request, f'Rent request successful! the car owner will be notified immediately.')
return super().form_valid(form)
def test_func(self):
return self.request.user.is_driver and self.request.user.is_active
car_detail.html
...
<h3>Place a Rent</h3>
<form action="" method="post" novalidate class="form-inline">
{% csrf_token %}
{% include 'app/bs4_form.html' with form=form %}
<button class="book-now-btn" type="submit">Rent</button>
</form>
...
Upvotes: 0
Views: 113
Reputation: 86
So that is a valid problem. For that you may have to provide the validation by overriding the save function for CarRent.
from django.core.exceptions import ValidationError
def save(self, *args, **kwargs):
has_reservation = self.__class__.objects.filter(car=self.car, driver=self.driver)
#reservation_valid = some logic to find if reservation is allowed
if not reservation_valid:
raise ValidationError("Driver reservation is not valid", code="drive_not_valid")
return super().save(*args, **kwargs)
Then in the view
try:
#try renting
except Exception as e:
if hasattr(e, "code"):
if e.code == "drive_not_valid":
#place your invalid view logic here
Upvotes: 0
Reputation: 86
For a proper solution you can define a inner Meta class for CarRent and define a unique_together attirbute for fields driver and car to avoid duplicate entry.
class CarRent(models.Model):
car = models.ForeignKey(Car, related_name='rented_car', on_delete=models.CASCADE)
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='driver_renting', on_delete=models.CASCADE)
rent_approval = models.BooleanField(null=True)
active_rent = models.BooleanField(default=False, null=True)
class Meta:
unique_together = ("driver", "car")
Upvotes: 0
Reputation: 3700
In your CarView class:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['rentAlreadyExists'] = CarRent.objects.filter(driver=self.request.user, car=self.object, active_rent=False).exists()
return context
Then in your template you can do:
{% if not rentAlreadyExists %}
... your form ...
{% endif %}
Upvotes: 1