From fa19b593d8a65ff4cddb4d3f5997b2338f8fe1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9DNyymix=E2=80=9D?= Date: Sat, 9 Aug 2025 20:23:30 +0300 Subject: [PATCH] Add FuelPurchase model, List, Create views and templates --- config/settings.py | 4 +- main/admin.py | 4 +- main/forms.py | 31 +++++++++++++ main/migrations/0001_initial.py | 29 ++++++++++++ main/models.py | 44 ++++++++++++++++++- main/templates/main/fuelpurchase_add.html | 51 ++++++++++++++++++++++ main/templates/main/fuelpurchase_list.html | 35 +++++++++++++++ main/urls.py | 3 +- main/views.py | 19 ++++++++ templates/base.html | 26 +++++++++++ 10 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 main/forms.py create mode 100644 main/migrations/0001_initial.py create mode 100644 main/templates/main/fuelpurchase_add.html create mode 100644 main/templates/main/fuelpurchase_list.html create mode 100644 templates/base.html diff --git a/config/settings.py b/config/settings.py index ea8f284..1d78eaf 100644 --- a/config/settings.py +++ b/config/settings.py @@ -55,7 +55,9 @@ ROOT_URLCONF = 'config.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [ + 'templates', + ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/main/admin.py b/main/admin.py index 8c38f3f..3b7cd99 100644 --- a/main/admin.py +++ b/main/admin.py @@ -1,3 +1,5 @@ from django.contrib import admin -# Register your models here. +from .models import FuelPurchase + +admin.site.register(FuelPurchase) diff --git a/main/forms.py b/main/forms.py new file mode 100644 index 0000000..39fc414 --- /dev/null +++ b/main/forms.py @@ -0,0 +1,31 @@ +from django import forms + +from .models import FuelPurchase + + +class FuelPurchaseForm(forms.ModelForm): + class Meta: + model = FuelPurchase + fields = ['purchase_date', 'total_cost', 'price_per_litre', 'amount_litres'] + widgets = { + 'purchase_date': forms.DateInput(attrs={ + 'type': 'date', + 'class': 'uk-input' + }), + 'total_cost': forms.NumberInput(attrs={ + 'step': '0.01', + 'class': 'uk-input', + 'id': 'id_total_cost' + }), + 'price_per_litre': forms.NumberInput(attrs={ + 'step': '0.001', + 'class': 'uk-input', + 'id': 'id_price_per_litre' + }), + 'amount_litres': forms.NumberInput(attrs={ + 'step': '0.01', + 'class': 'uk-input', + 'id': 'id_amount_litres', + 'readonly': True + }), + } diff --git a/main/migrations/0001_initial.py b/main/migrations/0001_initial.py new file mode 100644 index 0000000..fd8440e --- /dev/null +++ b/main/migrations/0001_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 5.2.5 on 2025-08-09 17:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='FuelPurchase', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('purchase_date', models.DateField(verbose_name='Purchase Date')), + ('total_cost', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Total Cost (€)')), + ('price_per_litre', models.DecimalField(decimal_places=3, max_digits=6, verbose_name='Price per Litre (€)')), + ('amount_litres', models.DecimalField(decimal_places=2, max_digits=7, verbose_name='Amount (litres)')), + ], + options={ + 'verbose_name': 'Fuel Purchase', + 'verbose_name_plural': 'Fuel Purchases', + 'constraints': [models.UniqueConstraint(fields=('purchase_date', 'total_cost', 'price_per_litre', 'amount_litres'), name='unique_fuel_purchase'), models.CheckConstraint(condition=models.Q(('total_cost__gt', 0), ('total_cost__lt', 100)), name='total_cost_range'), models.CheckConstraint(condition=models.Q(('price_per_litre__gt', 0), ('price_per_litre__lt', 5)), name='price_per_litre_range'), models.CheckConstraint(condition=models.Q(('amount_litres__gt', 0), ('amount_litres__lt', 100)), name='amount_litres_range')], + }, + ), + ] diff --git a/main/models.py b/main/models.py index 71a8362..661dfd8 100644 --- a/main/models.py +++ b/main/models.py @@ -1,3 +1,45 @@ from django.db import models +from django.db.models import F, Q -# Create your models here. + +class FuelPurchase(models.Model): + purchase_date = models.DateField(null=False, blank=False, verbose_name="Purchase Date") + total_cost = models.DecimalField(null=False, blank=False, max_digits=10, decimal_places=2, verbose_name="Total Cost (€)") + price_per_litre = models.DecimalField(null=False, blank=False, max_digits=6, decimal_places=3, verbose_name="Price per Litre (€)") + amount_litres = models.DecimalField(null=False, blank=False, max_digits=7, decimal_places=2, verbose_name="Amount (litres)") + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=[ + 'purchase_date', + 'total_cost', + 'price_per_litre', + 'amount_litres', + ], + name='unique_fuel_purchase' + ), + models.CheckConstraint( + check=Q(total_cost__gt=0) & Q(total_cost__lt=100), + name="total_cost_range" + ), + models.CheckConstraint( + check=Q(price_per_litre__gt=0) & Q(price_per_litre__lt=5), + name="price_per_litre_range" + ), + models.CheckConstraint( + check=Q(amount_litres__gt=0) & Q(amount_litres__lt=100), + name="amount_litres_range" + ), + ] + verbose_name = "Fuel Purchase" + verbose_name_plural = "Fuel Purchases" + + def save(self, *args, **kwargs): + if not self.amount_litres and self.price_per_litre: + self.amount_litres = self.total_cost / self.price_per_litre + super().save(*args, **kwargs) + + def __str__(self): + date_str = self.purchase_date.strftime("%d.%m.%Y") + return f"{date_str} : {self.total_cost} € - {self.price_per_litre} €/L" diff --git a/main/templates/main/fuelpurchase_add.html b/main/templates/main/fuelpurchase_add.html new file mode 100644 index 0000000..54b88e6 --- /dev/null +++ b/main/templates/main/fuelpurchase_add.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} + +{% block title %}Add Fuel Purchase{% endblock %} + +{% block content %} +

Add Fuel Purchase

+ +
+ {% csrf_token %} + + {% for field in form %} +
+ +
+ {{ field }} + {% if field.help_text %} +

{{ field.help_text }}

+ {% endif %} + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} +
+
+ {% endfor %} + + + Cancel + +
+ + +{% endblock %} diff --git a/main/templates/main/fuelpurchase_list.html b/main/templates/main/fuelpurchase_list.html new file mode 100644 index 0000000..45c6ee0 --- /dev/null +++ b/main/templates/main/fuelpurchase_list.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} + +{% block title %}Fuel Purchases{% endblock %} + +{% block content %} +
+

Fuel Purchases

+ Add Purchase +
+ +{% if purchases %} + + + + + + + + + + + {% for purchase in purchases %} + + + + + + + {% endfor %} + +
DateTotal Cost (€)Price/Litre (€)Amount (litres)
{{ purchase.purchase_date|date:"d.m.Y" }}{{ purchase.total_cost }}{{ purchase.price_per_litre }}{{ purchase.amount_litres }}
+{% else %} +

No purchases recorded yet.

+{% endif %} +{% endblock %} diff --git a/main/urls.py b/main/urls.py index 5119061..dd70134 100644 --- a/main/urls.py +++ b/main/urls.py @@ -3,5 +3,6 @@ from django.urls import path from . import views urlpatterns = [ - path("", views.index, name="index"), + path("", views.FuelPurchaseListView.as_view(), name="fuelpurchase_list"), + path("add/", views.FuelPurchaseCreateView.as_view(), name="fuelpurchase_add"), ] diff --git a/main/views.py b/main/views.py index 2848eff..2c54c44 100644 --- a/main/views.py +++ b/main/views.py @@ -1,6 +1,25 @@ from django.http import HttpResponse from django.shortcuts import render +from django.urls import reverse_lazy +from django.views.generic import CreateView, ListView + +from .forms import FuelPurchaseForm +from .models import FuelPurchase def index(request): return HttpResponse("Hello, world.") + + +class FuelPurchaseListView(ListView): + model = FuelPurchase + template_name = "main/fuelpurchase_list.html" + context_object_name = "purchases" + ordering = ['-purchase_date'] + + +class FuelPurchaseCreateView(CreateView): + model = FuelPurchase + form_class = FuelPurchaseForm + template_name = "main/fuelpurchase_add.html" + success_url = "/" diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..e585e38 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,26 @@ +{% load static %} + + + + + + {% block title %}Fuel Tracker{% endblock %} + + + + + + + + + + +
+ {% block content %}{% endblock %} +
+ + + + + +