diff --git a/taxi/forms.py b/taxi/forms.py new file mode 100644 index 000000000..fd1e47d00 --- /dev/null +++ b/taxi/forms.py @@ -0,0 +1,26 @@ +from django import forms +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Submit +from .models import Car, Manufacturer + + +class CarForm(forms.ModelForm): + class Meta: + model = Car + fields = ["model", "manufacturer", "drivers"] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.add_input(Submit("submit", "Save")) + + +class ManufacturerForm(forms.ModelForm): + class Meta: + model = Manufacturer + fields = ["name", "country"] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.add_input(Submit("submit", "Save")) diff --git a/taxi/migrations/0001_initial.py b/taxi/migrations/0001_initial.py index f1fc34ab7..fc40d98dc 100644 --- a/taxi/migrations/0001_initial.py +++ b/taxi/migrations/0001_initial.py @@ -13,54 +13,169 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), + ("auth", "0012_alter_user_first_name_max_length"), ] operations = [ migrations.CreateModel( - name='Driver', + name="Driver", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('license_number', models.CharField(max_length=255, unique=True)), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("password", models.CharField(max_length=128, verbose_name="password")), + ( + "last_login", + models.DateTimeField( + blank=True, null=True, verbose_name="last login" + ), + ), + ( + "is_superuser", + models.BooleanField( + default=False, + help_text="Designates that this user has all permissions without explicitly assigning them.", + verbose_name="superuser status", + ), + ), + ( + "username", + models.CharField( + error_messages={ + "unique": "A user with that username already exists." + }, + help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", + max_length=150, + unique=True, + validators=[ + django.contrib.auth.validators.UnicodeUsernameValidator() + ], + verbose_name="username", + ), + ), + ( + "first_name", + models.CharField( + blank=True, max_length=150, verbose_name="first name" + ), + ), + ( + "last_name", + models.CharField( + blank=True, max_length=150, verbose_name="last name" + ), + ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="email address" + ), + ), + ( + "is_staff", + models.BooleanField( + default=False, + help_text="Designates whether the user can log into this admin site.", + verbose_name="staff status", + ), + ), + ( + "is_active", + models.BooleanField( + default=True, + help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", + verbose_name="active", + ), + ), + ( + "date_joined", + models.DateTimeField( + default=django.utils.timezone.now, verbose_name="date joined" + ), + ), + ("license_number", models.CharField(max_length=255, unique=True)), + ( + "groups", + models.ManyToManyField( + blank=True, + help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.", + related_name="user_set", + related_query_name="user", + to="auth.Group", + verbose_name="groups", + ), + ), + ( + "user_permissions", + models.ManyToManyField( + blank=True, + help_text="Specific permissions for this user.", + related_name="user_set", + related_query_name="user", + to="auth.Permission", + verbose_name="user permissions", + ), + ), ], options={ - 'verbose_name': 'driver', - 'verbose_name_plural': 'drivers', + "verbose_name": "driver", + "verbose_name_plural": "drivers", }, managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ("objects", django.contrib.auth.models.UserManager()), ], ), migrations.CreateModel( - name='Manufacturer', + name="Manufacturer", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=255, unique=True)), - ('country', models.CharField(max_length=255)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255, unique=True)), + ("country", models.CharField(max_length=255)), ], options={ - 'ordering': ['name'], + "ordering": ["name"], }, ), migrations.CreateModel( - name='Car', + name="Car", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('model', models.CharField(max_length=255)), - ('drivers', models.ManyToManyField(related_name='cars', to=settings.AUTH_USER_MODEL)), - ('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='taxi.manufacturer')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("model", models.CharField(max_length=255)), + ( + "drivers", + models.ManyToManyField( + related_name="cars", to=settings.AUTH_USER_MODEL + ), + ), + ( + "manufacturer", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="taxi.manufacturer", + ), + ), ], ), ] diff --git a/taxi/urls.py b/taxi/urls.py index c663d6e22..c07f4a143 100644 --- a/taxi/urls.py +++ b/taxi/urls.py @@ -7,6 +7,12 @@ DriverListView, DriverDetailView, ManufacturerListView, + CarCreateView, + CarUpdateView, + CarDeleteView, + ManufacturerCreateView, + ManufacturerUpdateView, + ManufacturerDeleteView, ) urlpatterns = [ @@ -20,7 +26,27 @@ path("cars//", CarDetailView.as_view(), name="car-detail"), path("drivers/", DriverListView.as_view(), name="driver-list"), path( - "drivers//", DriverDetailView.as_view(), name="driver-detail" + "drivers//", + DriverDetailView.as_view(), + name="driver-detail" + ), + path("cars/create/", CarCreateView.as_view(), name="car-create"), + path("cars//update/", CarUpdateView.as_view(), name="car-update"), + path("cars//delete/", CarDeleteView.as_view(), name="car-delete"), + path( + "manufacturers/create/", + ManufacturerCreateView.as_view(), + name="manufacturer-create", + ), + path( + "manufacturers//update/", + ManufacturerUpdateView.as_view(), + name="manufacturer-update", + ), + path( + "manufacturers//delete/", + ManufacturerDeleteView.as_view(), + name="manufacturer-delete", ), ] diff --git a/taxi/views.py b/taxi/views.py index 4a99a2cd9..e4724d983 100644 --- a/taxi/views.py +++ b/taxi/views.py @@ -2,8 +2,11 @@ from django.shortcuts import render from django.views import generic from django.contrib.auth.mixins import LoginRequiredMixin +from django.urls import reverse_lazy +from django.views.generic import CreateView, UpdateView, DeleteView from .models import Driver, Car, Manufacturer +from .forms import CarForm, ManufacturerForm @login_required @@ -52,3 +55,43 @@ class DriverListView(LoginRequiredMixin, generic.ListView): class DriverDetailView(LoginRequiredMixin, generic.DetailView): model = Driver queryset = Driver.objects.all().prefetch_related("cars__manufacturer") + + +class CarCreateView(CreateView): + model = Car + form_class = CarForm + template_name = "taxi/car_form.html" + success_url = reverse_lazy("taxi:car-list") + + +class CarUpdateView(UpdateView): + model = Car + form_class = CarForm + template_name = "taxi/car_form.html" + success_url = reverse_lazy("taxi:car-list") + + +class CarDeleteView(DeleteView): + model = Car + template_name = "taxi/car_confirm_delete.html" + success_url = reverse_lazy("taxi:car-list") + + +class ManufacturerCreateView(CreateView): + model = Manufacturer + form_class = ManufacturerForm + template_name = "taxi/manufacturer_form.html" + success_url = reverse_lazy("taxi:manufacturer-list") + + +class ManufacturerUpdateView(UpdateView): + model = Manufacturer + form_class = ManufacturerForm + template_name = "taxi/manufacturer_form.html" + success_url = reverse_lazy("taxi:manufacturer-list") + + +class ManufacturerDeleteView(DeleteView): + model = Manufacturer + template_name = "taxi/manufacturer_confirm_delete.html" + success_url = reverse_lazy("taxi:manufacturer-list") diff --git a/taxi_service/settings.py b/taxi_service/settings.py index d89c45643..15226241a 100644 --- a/taxi_service/settings.py +++ b/taxi_service/settings.py @@ -44,6 +44,7 @@ "django.contrib.staticfiles", "debug_toolbar", "taxi", + "crispy_forms", ] MIDDLEWARE = [ @@ -140,3 +141,5 @@ # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +CRISPY_TEMPLATE_PACK = "bootstrap4" diff --git a/templates/taxi/car_confirm_delete.html b/templates/taxi/car_confirm_delete.html new file mode 100644 index 000000000..040531406 --- /dev/null +++ b/templates/taxi/car_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +

Delete Car

+

Are you sure you want to delete "{{ object }}"?

+
+ {% csrf_token %} + + Cancel +
+{% endblock %} \ No newline at end of file diff --git a/templates/taxi/car_form.html b/templates/taxi/car_form.html new file mode 100644 index 000000000..44f2c3318 --- /dev/null +++ b/templates/taxi/car_form.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% load crispy_forms_tags %} + +{% block content %} +

{% if object %}Edit{% else %}Add{% endif %} Car

+
+ {% csrf_token %} + {{ form|crispy }} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/taxi/car_list.html b/templates/taxi/car_list.html index e107b5797..37cc2b0cb 100644 --- a/templates/taxi/car_list.html +++ b/templates/taxi/car_list.html @@ -2,12 +2,15 @@ {% block content %}

Car list

+ Add Car {% if car_list %} diff --git a/templates/taxi/manufacturer_confirm_delete.html b/templates/taxi/manufacturer_confirm_delete.html new file mode 100644 index 000000000..5e3fceb70 --- /dev/null +++ b/templates/taxi/manufacturer_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} +

Delete Manufacturer

+

Are you sure you want to delete "{{ object }}"?

+
+ {% csrf_token %} + + Cancel +
+{% endblock %} \ No newline at end of file diff --git a/templates/taxi/manufacturer_form.html b/templates/taxi/manufacturer_form.html new file mode 100644 index 000000000..7ab054a4f --- /dev/null +++ b/templates/taxi/manufacturer_form.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% load crispy_forms_tags %} + +{% block content %} +

{% if object %}Edit{% else %}Add{% endif %} Manufacturer

+
+ {% csrf_token %} + {{ form|crispy }} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/taxi/manufacturer_list.html b/templates/taxi/manufacturer_list.html index 2a31bcf60..1f803c754 100644 --- a/templates/taxi/manufacturer_list.html +++ b/templates/taxi/manufacturer_list.html @@ -1,8 +1,8 @@ {% extends "base.html" %} {% block content %} -

Manufacturer List -

+

Manufacturer List

+ Add Manufacturer {% if manufacturer_list %} @@ -10,6 +10,7 @@

Manufacturer List

+ {% for manufacturer in manufacturer_list %} @@ -23,6 +24,10 @@

Manufacturer List

+ {% endfor %}
ID Name CountryActions
{{ manufacturer.country }} + Edit + Delete +