From 28897e6c1d01a62cc6ecc8f495cf3620452afa7b Mon Sep 17 00:00:00 2001 From: Tymofii Pavliohlo Date: Wed, 1 Jan 2025 21:24:25 +0100 Subject: [PATCH] Solution --- taxi/forms.py | 52 +++++++++++++++++++++++ taxi/urls.py | 15 +++++++ taxi/views.py | 35 ++++++++++++++- templates/taxi/car_detail.html | 27 ++++++++---- templates/taxi/driver_confirm_delete.html | 10 +++++ templates/taxi/driver_detail.html | 6 +++ templates/taxi/driver_form.html | 12 ++++++ templates/taxi/driver_list.html | 2 +- 8 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 taxi/forms.py create mode 100644 templates/taxi/driver_confirm_delete.html create mode 100644 templates/taxi/driver_form.html diff --git a/taxi/forms.py b/taxi/forms.py new file mode 100644 index 000000000..fa033542a --- /dev/null +++ b/taxi/forms.py @@ -0,0 +1,52 @@ +from django import forms +from django.contrib.auth import get_user_model +from django.contrib.auth.forms import UserCreationForm +from django.forms import ValidationError +from taxi.models import Driver, Car + + +class CarForm(forms.ModelForm): + drivers = forms.ModelMultipleChoiceField( + queryset=get_user_model().objects.all(), + widget=forms.CheckboxSelectMultiple, + required=False, + ) + + class Meta: + model = Car + fields = "__all__" + + +class DriverCreationForm(UserCreationForm): + class Meta(UserCreationForm.Meta): + model = Driver + fields = UserCreationForm.Meta.fields + ( + "first_name", + "last_name", + "license_number", + ) + + def clean_license_number(self): + return validate_license_number(self.cleaned_data["license_number"]) + + +class DriverLicenseUpdateForm(forms.ModelForm): + class Meta: + model = Driver + fields = ("license_number",) + + def clean_license_number(self): + return validate_license_number(self.cleaned_data["license_number"]) + + +def validate_license_number(license_number: str) -> str: + + if len(license_number) != 8: + raise ValidationError("License must consist only of 8 characters") + elif not license_number[:3].isalpha() or not license_number[:3].isupper(): + raise ValidationError( + "First 3 characters of license are not uppercase or letters" + ) + elif not license_number[3:].isdigit(): + raise ValidationError("Last 5 characters are not digits") + return license_number \ No newline at end of file diff --git a/taxi/urls.py b/taxi/urls.py index 4f017a999..bea6279f6 100644 --- a/taxi/urls.py +++ b/taxi/urls.py @@ -13,6 +13,9 @@ ManufacturerCreateView, ManufacturerUpdateView, ManufacturerDeleteView, + DriverCreateView, + DriverDeleteView, + DriverLicenseUpdateView, toggle_car ) urlpatterns = [ @@ -43,9 +46,21 @@ path("cars//update/", CarUpdateView.as_view(), name="car-update"), path("cars//delete/", CarDeleteView.as_view(), name="car-delete"), path("drivers/", DriverListView.as_view(), name="driver-list"), + path("drivers/create/", DriverCreateView.as_view(), name="driver-create"), path( "drivers//", DriverDetailView.as_view(), name="driver-detail" ), + path( + "drivers//delete/", + DriverDeleteView.as_view(), + name="driver-delete", + ), + path("cars//toggle-car/", toggle_car, name="toggle-car"), + path( + "drivers//update/", + DriverLicenseUpdateView.as_view(), + name="driver-update", + ), ] app_name = "taxi" diff --git a/taxi/views.py b/taxi/views.py index 0789d616e..0508f0b2c 100644 --- a/taxi/views.py +++ b/taxi/views.py @@ -1,9 +1,13 @@ from django.contrib.auth.decorators import login_required +from django.http import HttpResponseRedirect from django.shortcuts import render from django.urls import reverse_lazy from django.views import generic from django.contrib.auth.mixins import LoginRequiredMixin +from taxi.forms import CarForm, DriverCreationForm, DriverLicenseUpdateForm + +from .forms import DriverCreationForm from .models import Driver, Car, Manufacturer @@ -64,13 +68,13 @@ class CarDetailView(LoginRequiredMixin, generic.DetailView): class CarCreateView(LoginRequiredMixin, generic.CreateView): model = Car - fields = "__all__" + form_class = CarForm success_url = reverse_lazy("taxi:car-list") class CarUpdateView(LoginRequiredMixin, generic.UpdateView): model = Car - fields = "__all__" + form_class = CarForm success_url = reverse_lazy("taxi:car-list") @@ -87,3 +91,30 @@ class DriverListView(LoginRequiredMixin, generic.ListView): class DriverDetailView(LoginRequiredMixin, generic.DetailView): model = Driver queryset = Driver.objects.all().prefetch_related("cars__manufacturer") + + +class DriverCreateView(LoginRequiredMixin, generic.CreateView): + model = Driver + form_class = DriverCreationForm + success_url = reverse_lazy("taxi:driver-list") + + +class DriverLicenseUpdateView(LoginRequiredMixin, generic.UpdateView): + model = Driver + form_class = DriverLicenseUpdateForm + success_url = reverse_lazy("taxi:driver-list") + + +class DriverDeleteView(LoginRequiredMixin, generic.DeleteView): + model = Driver + success_url = reverse_lazy("taxi:driver-list") + + +@login_required +def toggle_car(request, pk): + driver = Driver.objects.get(id=request.user.id) + if Car.objects.get(id=pk) in driver.cars.all(): + driver.cars.remove(pk) + else: + driver.cars.add(pk) + return HttpResponseRedirect(reverse_lazy("taxi:car-detail", args=[pk])) \ No newline at end of file diff --git a/templates/taxi/car_detail.html b/templates/taxi/car_detail.html index 78197443a..8d9893465 100644 --- a/templates/taxi/car_detail.html +++ b/templates/taxi/car_detail.html @@ -3,20 +3,31 @@ {% block content %}

{{ car.model }} - - Delete - - - - Update - +

Manufacturer: ({{ car.manufacturer.name }}, {{ car.manufacturer.country }})

-

Drivers

+

Drivers + {%if car in user.cars.all %} + + Delete me from this car + + {%else%} + + Assign me to this car + + {% endif %} +


    {% for driver in car.drivers.all %}
  • {{ driver.username }} ({{ driver.first_name }} {{ driver.last_name }})
  • {% endfor %}
+ + Update + + + Delete + + {% endblock %} diff --git a/templates/taxi/driver_confirm_delete.html b/templates/taxi/driver_confirm_delete.html new file mode 100644 index 000000000..c432f7b9e --- /dev/null +++ b/templates/taxi/driver_confirm_delete.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Delete Driver?

+
+ {% csrf_token %} + + +
+{% endblock %} diff --git a/templates/taxi/driver_detail.html b/templates/taxi/driver_detail.html index 788084648..0ac6a5a13 100644 --- a/templates/taxi/driver_detail.html +++ b/templates/taxi/driver_detail.html @@ -23,4 +23,10 @@

Cars

No cars!

{% endfor %} + + Update + + + Delete + {% endblock %} diff --git a/templates/taxi/driver_form.html b/templates/taxi/driver_form.html new file mode 100644 index 000000000..fd2331773 --- /dev/null +++ b/templates/taxi/driver_form.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% load crispy_forms_filters %} + +{% block content %} +

{{ object|yesno:"Update,Create" }} driver

+
+ {% csrf_token %} + {{ form|crispy }} + + +
+{% endblock %} diff --git a/templates/taxi/driver_list.html b/templates/taxi/driver_list.html index b740f95ea..20e4ddf26 100644 --- a/templates/taxi/driver_list.html +++ b/templates/taxi/driver_list.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block content %} -

Driver List +

Driver List Create

{% if driver_list %}