diff --git a/.flake8 b/.flake8 index b5381af38..86537c9f4 100644 --- a/.flake8 +++ b/.flake8 @@ -5,6 +5,6 @@ max-line-length = 79 max-complexity = 18 select = B,C,E,F,W,T4,B9,Q0,N8,VNE exclude = - **migrations - venv + */migrations/* + .venv tests \ No newline at end of file diff --git a/taxi/forms.py b/taxi/forms.py new file mode 100644 index 000000000..f674ae2d0 --- /dev/null +++ b/taxi/forms.py @@ -0,0 +1,57 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm + +from taxi.models import Driver, Car + + +def clean_license_number(license_number: str) -> str: + if ( + len(license_number) != 8 + or not license_number[:3].isupper() + or not license_number[3:].isdigit() + ): + raise forms.ValidationError("License number is invalid") + return license_number + + +class DriverCreateForm(UserCreationForm): + + license_number = forms.CharField( + required=True, + label="License Number", + validators=[clean_license_number], + ) + + class Meta: + model = Driver + fields = UserCreationForm.Meta.fields + ( + "first_name", + "last_name", + "license_number", + ) + + +class LicenseUpdateForm(forms.ModelForm): + + license_number = forms.CharField( + required=True, + label="License Number", + validators=[clean_license_number], + ) + + class Meta: + model = Driver + fields = ("license_number",) + + +class CarCreateForm(forms.ModelForm): + drivers = forms.ModelMultipleChoiceField( + queryset=Driver.objects.all(), + required=False, + widget=forms.CheckboxSelectMultiple(), + label="Drivers", + ) + + class Meta: + model = Car + fields = "__all__" 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 4f017a999..2a7de4e9e 100644 --- a/taxi/urls.py +++ b/taxi/urls.py @@ -13,6 +13,11 @@ ManufacturerCreateView, ManufacturerUpdateView, ManufacturerDeleteView, + DriverCreateView, + DriverLicenseUpdateView, + DriverDeleteView, + car_add_driver, + car_delete_driver, ) urlpatterns = [ @@ -44,7 +49,34 @@ path("cars//delete/", CarDeleteView.as_view(), name="car-delete"), path("drivers/", DriverListView.as_view(), name="driver-list"), path( - "drivers//", DriverDetailView.as_view(), name="driver-detail" + "drivers//", + DriverDetailView.as_view(), + name="driver-detail" + ), + path( + "drivers/create/", + DriverCreateView.as_view(), + name="driver-create" + ), + path( + "drivers//license_update/", + DriverLicenseUpdateView.as_view(), + name="driver-license-update", + ), + path( + "drivers//delete/", + DriverDeleteView.as_view(), + name="driver-delete" + ), + path( + "car//add_driver/", + car_add_driver, + name="car-add-driver" + ), + path( + "car//delete_driver/", + car_delete_driver, + name="car-delete-driver" ), ] diff --git a/taxi/views.py b/taxi/views.py index 0789d616e..80dca9b45 100644 --- a/taxi/views.py +++ b/taxi/views.py @@ -1,9 +1,11 @@ from django.contrib.auth.decorators import login_required -from django.shortcuts import render +from django.http import HttpRequest, HttpResponse, HttpResponseRedirect +from django.shortcuts import render, get_object_or_404 from django.urls import reverse_lazy from django.views import generic from django.contrib.auth.mixins import LoginRequiredMixin +from .forms import DriverCreateForm, LicenseUpdateForm, CarCreateForm from .models import Driver, Car, Manufacturer @@ -64,7 +66,7 @@ class CarDetailView(LoginRequiredMixin, generic.DetailView): class CarCreateView(LoginRequiredMixin, generic.CreateView): model = Car - fields = "__all__" + form_class = CarCreateForm success_url = reverse_lazy("taxi:car-list") @@ -87,3 +89,52 @@ 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 = DriverCreateForm + + +class DriverLicenseUpdateView(LoginRequiredMixin, generic.UpdateView): + model = Driver + form_class = LicenseUpdateForm + + def get_success_url(self): + return reverse_lazy( + "taxi:driver-detail", + kwargs={"pk": self.object.pk} + ) + + +class DriverDeleteView(LoginRequiredMixin, generic.DeleteView): + model = Driver + success_url = reverse_lazy("taxi:driver-list") + + +def car_add_driver(request: HttpRequest, pk: int) -> HttpResponseRedirect: + car = get_object_or_404(Car, pk=pk) + if request.user.is_authenticated: + driver = request.user + car.drivers.add(driver) + return HttpResponseRedirect( + reverse_lazy + ( + "taxi:car-detail", + kwargs={"pk": car.pk} + ) + ) + + +def car_delete_driver(request: HttpRequest, pk: int) -> HttpResponseRedirect: + car = get_object_or_404(Car, pk=pk) + if request.user.is_authenticated: + driver = request.user + car.drivers.remove(driver) + return HttpResponseRedirect( + reverse_lazy + ( + "taxi:car-detail", + kwargs={"pk": car.pk} + ) + ) diff --git a/taxi_service/settings.py b/taxi_service/settings.py index 8f98f33e6..fb7845edf 100644 --- a/taxi_service/settings.py +++ b/taxi_service/settings.py @@ -20,9 +20,7 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = ( - "django-insecure-8ovil3xu6=eaoqd#-#&ricv159p0pypoh5_lgm*)-dfcjqe=yc" -) +SECRET_KEY = "django-insecure-8ovil3xu6=eaoqd#-#&ricv159p0pypoh5_lgm*)-dfcjqe=yc" # SECURITY WARNING: don"t run with debug turned on in production! DEBUG = True @@ -101,16 +99,13 @@ "UserAttributeSimilarityValidator", }, { - "NAME": "django.contrib.auth.password_validation." - "MinimumLengthValidator", + "NAME": "django.contrib.auth.password_validation." "MinimumLengthValidator", }, { - "NAME": "django.contrib.auth.password_validation." - "CommonPasswordValidator", + "NAME": "django.contrib.auth.password_validation." "CommonPasswordValidator", }, { - "NAME": "django.contrib.auth.password_validation." - "NumericPasswordValidator", + "NAME": "django.contrib.auth.password_validation." "NumericPasswordValidator", }, ] diff --git a/taxi_service/urls.py b/taxi_service/urls.py index a2341345c..4e245a740 100644 --- a/taxi_service/urls.py +++ b/taxi_service/urls.py @@ -13,6 +13,7 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path("blog/", include("blog.urls")) """ + from django.contrib import admin from django.urls import path, include from django.conf import settings diff --git a/taxi_service_db_data.json b/taxi_service_db_data.json index 252fcf94a..4f9ade07f 100644 --- a/taxi_service_db_data.json +++ b/taxi_service_db_data.json @@ -1,503 +1,361 @@ [ - { - "model": "taxi.manufacturer", - "pk": 1, - "fields": { - "name": "Lincoln", - "country": "USA" - } - }, - { - "model": "taxi.manufacturer", - "pk": 2, - "fields": { - "name": "Ford Motor Company", - "country": "USA" - } - }, - { - "model": "taxi.manufacturer", - "pk": 3, - "fields": { - "name": "General Motors", - "country": "USA" - } - }, - { - "model": "taxi.manufacturer", - "pk": 4, - "fields": { - "name": "Toyota", - "country": "Japan" - } - }, - { - "model": "taxi.manufacturer", - "pk": 5, - "fields": { - "name": "Suzuki", - "country": "Japan" - } - }, - { - "model": "taxi.manufacturer", - "pk": 6, - "fields": { - "name": "Mitsubishi", - "country": "Japan" - } - }, - { - "model": "taxi.manufacturer", - "pk": 7, - "fields": { - "name": "Volkswagen", - "country": "Germany" - } - }, - { - "model": "taxi.manufacturer", - "pk": 8, - "fields": { - "name": "Daimler", - "country": "Germany" - } - }, - { - "model": "taxi.manufacturer", - "pk": 9, - "fields": { - "name": "FCA", - "country": "Italy" - } - }, - { - "model": "taxi.manufacturer", - "pk": 10, - "fields": { - "name": "Renault", - "country": "France" - } - }, - { - "model": "taxi.manufacturer", - "pk": 11, - "fields": { - "name": "SAIC", - "country": "China" - } - }, - { - "model": "taxi.manufacturer", - "pk": 12, - "fields": { - "name": "Mazda", - "country": "Japan" - } - }, - { - "model": "taxi.manufacturer", - "pk": 13, - "fields": { - "name": "BAIC", - "country": "China" - } - }, - { - "model": "taxi.manufacturer", - "pk": 14, - "fields": { - "name": "BMW", - "country": "Germany" - } - }, - { - "model": "taxi.driver", - "pk": 1, - "fields": { - "password": "pbkdf2_sha256$320000$6uM28XWOFX6ewyloJzjqmt$L+ZhofPylneoaL2iZS4sZu4ZMUNb4oIevfAdzOMn/eE=", - "last_login": "2022-08-08T14:14:03Z", - "is_superuser": true, - "username": "admin.user", - "first_name": "Admin", - "last_name": "User", - "email": "admin.user@taxi.com", - "is_staff": true, - "is_active": true, - "date_joined": "2022-08-08T13:58:29Z", - "license_number": "ADM56984", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 2, - "fields": { - "password": "pbkdf2_sha256$320000$73Z1Y57bcoscZ37s9rE9v0$4SEQ0TtXwJKzO5/CRdFSrTifatiPjkZ38gM2H8Kqsdg=", - "last_login": null, - "is_superuser": false, - "username": "joyce.byers", - "first_name": "Joyce", - "last_name": "Byers", - "email": "joyce.byers@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-08T14:17:04Z", - "license_number": "JOY26458", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 3, - "fields": { - "password": "pbkdf2_sha256$320000$QtPol3T7x9quBj4BnbnVwW$UwT4kihkRfSvQEWEeuqVKwMgis2ikKVZfJDBcQMvOKY=", - "last_login": null, - "is_superuser": false, - "username": "jim.hopper", - "first_name": "Jim", - "last_name": "Hopper", - "email": "jim.hopper@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-08T14:19:09Z", - "license_number": "JIM26531", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 4, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l1$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "jonathan.byers", - "first_name": "Jonathan", - "last_name": "Byers", - "email": "jonathan.byers@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-08T14:19:09Z", - "license_number": "JON26231", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 5, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l1$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "dustin.henderson", - "first_name": "Dustin", - "last_name": "Henderson", - "email": "dustin.henderson@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "DUS25131", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 6, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "mike.wheeler", - "first_name": "Mike", - "last_name": "Wheeler", - "email": "mike.wheeler@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "MIK25131", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 7, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "lucas.sinclair", - "first_name": "Lucas", - "last_name": "Sinclair", - "email": "lucas.sinclair@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "LUK35131", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 8, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "nancy.wheeler", - "first_name": "Nancy", - "last_name": "Wheeler", - "email": "nancy.wheeler@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "NAN34131", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 9, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "martin.brenner", - "first_name": "Martin", - "last_name": "Brenner", - "email": "martin.brenner@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "MAR34231", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 10, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "billy.hargrove", - "first_name": "Billy", - "last_name": "Hargrove", - "email": "billy.hargrove@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "BIL39231", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.driver", - "pk": 11, - "fields": { - "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", - "last_login": null, - "is_superuser": false, - "username": "bob.newby", - "first_name": "Bob", - "last_name": "Newby", - "email": "bob.newby@taxi.com", - "is_staff": false, - "is_active": true, - "date_joined": "2022-08-09T14:19:09Z", - "license_number": "BOB09631", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "taxi.car", - "pk": 1, - "fields": { - "model": "Lincoln Continental", - "manufacturer": 1, - "drivers": [ - 3 - ] - } - }, - { - "model": "taxi.car", - "pk": 2, - "fields": { - "model": "Toyota Yaris", - "manufacturer": 4, - "drivers": [ - 2, - 3 - ] - } - }, - { - "model": "taxi.car", - "pk": 3, - "fields": { - "model": "Suzuki Vitara", - "manufacturer": 5, - "drivers": [ - 1, - 2, - 5 - ] - } - }, - { - "model": "taxi.car", - "pk": 4, - "fields": { - "model": "Mitsubishi Eclipse", - "manufacturer": 6, - "drivers": [ - 1 - ] - } - }, - { - "model": "taxi.car", - "pk": 5, - "fields": { - "model": "Mitsubishi Lancer", - "manufacturer": 6, - "drivers": [ - 11 - ] - } - }, - { - "model": "taxi.car", - "pk": 6, - "fields": { - "model": "Ford Focus", - "manufacturer": 2, - "drivers": [ - 4 - ] - } - }, - { - "model": "taxi.car", - "pk": 7, - "fields": { - "model": "Cadillac Escalade", - "manufacturer": 3, - "drivers": [ - 5 - ] - } - }, - { - "model": "taxi.car", - "pk": 8, - "fields": { - "model": "Arcfox Alpha-S", - "manufacturer": 13, - "drivers": [ - ] - } - }, - { - "model": "taxi.car", - "pk": 9, - "fields": { - "model": "Beijing EX5", - "manufacturer": 13, - "drivers": [ - 9 - ] - } - }, - { - "model": "taxi.car", - "pk": 10, - "fields": { - "model": "MG 5 II", - "manufacturer": 11, - "drivers": [ - 8 - ] - } - }, - { - "model": "taxi.car", - "pk": 11, - "fields": { - "model": "Rising Auto ER6", - "manufacturer": 11, - "drivers": [ - 7, - 3 - ] - } - }, - { - "model": "taxi.car", - "pk": 12, - "fields": { - "model": "SP250", - "manufacturer": 8, - "drivers": [ - 6 - ] - } - }, - { - "model": "taxi.car", - "pk": 13, - "fields": { - "model": "Daimler Sovereign", - "manufacturer": 8, - "drivers": [ - 11, - 7 - ] - } - }, - { - "model": "taxi.car", - "pk": 14, - "fields": { - "model": "X5 M", - "manufacturer": 14, - "drivers": [ - 10 - ] - } - }, - { - "model": "taxi.car", - "pk": 15, - "fields": { - "model": "Floride", - "manufacturer": 10, - "drivers": [ - 9 - ] - } - }, - { - "model": "taxi.car", - "pk": 16, - "fields": { - "model": "MX-30", - "manufacturer": 12, - "drivers": [ - 4 - ] - } - } + { + "model": "taxi.manufacturer", + "pk": 1, + "fields": {"name": "Lincoln", "country": "USA"}, + }, + { + "model": "taxi.manufacturer", + "pk": 2, + "fields": {"name": "Ford Motor Company", "country": "USA"}, + }, + { + "model": "taxi.manufacturer", + "pk": 3, + "fields": {"name": "General Motors", "country": "USA"}, + }, + { + "model": "taxi.manufacturer", + "pk": 4, + "fields": {"name": "Toyota", "country": "Japan"}, + }, + { + "model": "taxi.manufacturer", + "pk": 5, + "fields": {"name": "Suzuki", "country": "Japan"}, + }, + { + "model": "taxi.manufacturer", + "pk": 6, + "fields": {"name": "Mitsubishi", "country": "Japan"}, + }, + { + "model": "taxi.manufacturer", + "pk": 7, + "fields": {"name": "Volkswagen", "country": "Germany"}, + }, + { + "model": "taxi.manufacturer", + "pk": 8, + "fields": {"name": "Daimler", "country": "Germany"}, + }, + { + "model": "taxi.manufacturer", + "pk": 9, + "fields": {"name": "FCA", "country": "Italy"}, + }, + { + "model": "taxi.manufacturer", + "pk": 10, + "fields": {"name": "Renault", "country": "France"}, + }, + { + "model": "taxi.manufacturer", + "pk": 11, + "fields": {"name": "SAIC", "country": "China"}, + }, + { + "model": "taxi.manufacturer", + "pk": 12, + "fields": {"name": "Mazda", "country": "Japan"}, + }, + { + "model": "taxi.manufacturer", + "pk": 13, + "fields": {"name": "BAIC", "country": "China"}, + }, + { + "model": "taxi.manufacturer", + "pk": 14, + "fields": {"name": "BMW", "country": "Germany"}, + }, + { + "model": "taxi.driver", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$320000$6uM28XWOFX6ewyloJzjqmt$L+ZhofPylneoaL2iZS4sZu4ZMUNb4oIevfAdzOMn/eE=", + "last_login": "2022-08-08T14:14:03Z", + "is_superuser": true, + "username": "admin.user", + "first_name": "Admin", + "last_name": "User", + "email": "admin.user@taxi.com", + "is_staff": true, + "is_active": true, + "date_joined": "2022-08-08T13:58:29Z", + "license_number": "ADM56984", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 2, + "fields": { + "password": "pbkdf2_sha256$320000$73Z1Y57bcoscZ37s9rE9v0$4SEQ0TtXwJKzO5/CRdFSrTifatiPjkZ38gM2H8Kqsdg=", + "last_login": null, + "is_superuser": false, + "username": "joyce.byers", + "first_name": "Joyce", + "last_name": "Byers", + "email": "joyce.byers@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-08T14:17:04Z", + "license_number": "JOY26458", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 3, + "fields": { + "password": "pbkdf2_sha256$320000$QtPol3T7x9quBj4BnbnVwW$UwT4kihkRfSvQEWEeuqVKwMgis2ikKVZfJDBcQMvOKY=", + "last_login": null, + "is_superuser": false, + "username": "jim.hopper", + "first_name": "Jim", + "last_name": "Hopper", + "email": "jim.hopper@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-08T14:19:09Z", + "license_number": "JIM26531", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 4, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l1$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "jonathan.byers", + "first_name": "Jonathan", + "last_name": "Byers", + "email": "jonathan.byers@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-08T14:19:09Z", + "license_number": "JON26231", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 5, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l1$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "dustin.henderson", + "first_name": "Dustin", + "last_name": "Henderson", + "email": "dustin.henderson@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "DUS25131", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 6, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "mike.wheeler", + "first_name": "Mike", + "last_name": "Wheeler", + "email": "mike.wheeler@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "MIK25131", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 7, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "lucas.sinclair", + "first_name": "Lucas", + "last_name": "Sinclair", + "email": "lucas.sinclair@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "LUK35131", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 8, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "nancy.wheeler", + "first_name": "Nancy", + "last_name": "Wheeler", + "email": "nancy.wheeler@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "NAN34131", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 9, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "martin.brenner", + "first_name": "Martin", + "last_name": "Brenner", + "email": "martin.brenner@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "MAR34231", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 10, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "billy.hargrove", + "first_name": "Billy", + "last_name": "Hargrove", + "email": "billy.hargrove@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "BIL39231", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.driver", + "pk": 11, + "fields": { + "password": "pbkdf2_sha256$320000$9yU0PLTDKlL02PedUtk2l2$LKjj8O1xGiPGEkDpjsHk87db1iLgt8dgDqECzcsivio", + "last_login": null, + "is_superuser": false, + "username": "bob.newby", + "first_name": "Bob", + "last_name": "Newby", + "email": "bob.newby@taxi.com", + "is_staff": false, + "is_active": true, + "date_joined": "2022-08-09T14:19:09Z", + "license_number": "BOB09631", + "groups": [], + "user_permissions": [], + }, + }, + { + "model": "taxi.car", + "pk": 1, + "fields": {"model": "Lincoln Continental", "manufacturer": 1, "drivers": [3]}, + }, + { + "model": "taxi.car", + "pk": 2, + "fields": {"model": "Toyota Yaris", "manufacturer": 4, "drivers": [2, 3]}, + }, + { + "model": "taxi.car", + "pk": 3, + "fields": {"model": "Suzuki Vitara", "manufacturer": 5, "drivers": [1, 2, 5]}, + }, + { + "model": "taxi.car", + "pk": 4, + "fields": {"model": "Mitsubishi Eclipse", "manufacturer": 6, "drivers": [1]}, + }, + { + "model": "taxi.car", + "pk": 5, + "fields": {"model": "Mitsubishi Lancer", "manufacturer": 6, "drivers": [11]}, + }, + { + "model": "taxi.car", + "pk": 6, + "fields": {"model": "Ford Focus", "manufacturer": 2, "drivers": [4]}, + }, + { + "model": "taxi.car", + "pk": 7, + "fields": {"model": "Cadillac Escalade", "manufacturer": 3, "drivers": [5]}, + }, + { + "model": "taxi.car", + "pk": 8, + "fields": {"model": "Arcfox Alpha-S", "manufacturer": 13, "drivers": []}, + }, + { + "model": "taxi.car", + "pk": 9, + "fields": {"model": "Beijing EX5", "manufacturer": 13, "drivers": [9]}, + }, + { + "model": "taxi.car", + "pk": 10, + "fields": {"model": "MG 5 II", "manufacturer": 11, "drivers": [8]}, + }, + { + "model": "taxi.car", + "pk": 11, + "fields": {"model": "Rising Auto ER6", "manufacturer": 11, "drivers": [7, 3]}, + }, + { + "model": "taxi.car", + "pk": 12, + "fields": {"model": "SP250", "manufacturer": 8, "drivers": [6]}, + }, + { + "model": "taxi.car", + "pk": 13, + "fields": {"model": "Daimler Sovereign", "manufacturer": 8, "drivers": [11, 7]}, + }, + { + "model": "taxi.car", + "pk": 14, + "fields": {"model": "X5 M", "manufacturer": 14, "drivers": [10]}, + }, + { + "model": "taxi.car", + "pk": 15, + "fields": {"model": "Floride", "manufacturer": 10, "drivers": [9]}, + }, + { + "model": "taxi.car", + "pk": 16, + "fields": {"model": "MX-30", "manufacturer": 12, "drivers": [4]}, + }, ] diff --git a/templates/taxi/car_detail.html b/templates/taxi/car_detail.html index 78197443a..c3da4fad2 100644 --- a/templates/taxi/car_detail.html +++ b/templates/taxi/car_detail.html @@ -12,6 +12,11 @@

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

+ {% if user in car.drivers.all %} + Delete me from this car + {% else %} + Add me to this car + {% endif %}

Drivers


    diff --git a/templates/taxi/driver_confirm_delete.html b/templates/taxi/driver_confirm_delete.html new file mode 100644 index 000000000..4a7c1f40c --- /dev/null +++ b/templates/taxi/driver_confirm_delete.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} +{% load crispy_forms_filters %} + +{% block content %} +

    You sure that you want to delete {{ driver.first_name }} {{ driver.last_name }}

    +
    + {% csrf_token %} + +
    +{% endblock %} \ No newline at end of file diff --git a/templates/taxi/driver_detail.html b/templates/taxi/driver_detail.html index 788084648..c6573dd12 100644 --- a/templates/taxi/driver_detail.html +++ b/templates/taxi/driver_detail.html @@ -9,7 +9,12 @@

    Last name: {{ driver.last_name }}

    License number: {{ driver.license_number }}

    Is staff: {{ driver.is_staff }}

    - + + Update License Number + + + Delete +

    Cars

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

    {{ object|yesno:"Update license number,Create new driver" }}

    +
    + {% csrf_token %} + {{ form|crispy }} + + +
    +{% endblock %} \ No newline at end of file diff --git a/templates/taxi/driver_list.html b/templates/taxi/driver_list.html index b740f95ea..4279b626a 100644 --- a/templates/taxi/driver_list.html +++ b/templates/taxi/driver_list.html @@ -2,8 +2,8 @@ {% block content %}

    Driver List + Add new driver

    - {% if driver_list %} diff --git a/tests/test_taxi_service_user_form_and_validation.py b/tests/test_taxi_service_user_form_and_validation.py index d885092c9..10e706600 100644 --- a/tests/test_taxi_service_user_form_and_validation.py +++ b/tests/test_taxi_service_user_form_and_validation.py @@ -8,9 +8,7 @@ class ValidLicenseNumberFormTests(TestCase): @staticmethod def create_form(test_license_number): - return DriverLicenseUpdateForm( - data={"license_number": test_license_number} - ) + return DriverLicenseUpdateForm(data={"license_number": test_license_number}) def test_validation_license_number_with_valid_data(self): self.assertTrue(self.create_form("TES12345").is_valid()) @@ -67,6 +65,4 @@ def test_delete_driver(self): reverse("taxi:driver-delete", kwargs={"pk": driver.id}) ) self.assertEqual(response.status_code, 302) - self.assertFalse( - get_user_model().objects.filter(id=driver.id).exists() - ) + self.assertFalse(get_user_model().objects.filter(id=driver.id).exists())