Вычислить разницу между последовательными числами в рядах одной и той же модели

Я пытаюсь вычислить разницу между последовательными числовыми значениями в поле odometer_reading моей модели.
В моем Models.py есть поля, как показано ниже:

class Refuel(models.Model):
    vehicle = models.ForeignKey(Vehicle, blank=True, null=True, on_delete=models.SET_NULL)
    gaz_station = models.ForeignKey(
        GazStation, related_name=_("Station"), blank=True, null=True, on_delete=models.SET_NULL
    )
    odometer_reading = models.PositiveIntegerField(_("Compteur KM"), blank=True, null=True)
    snitch = models.PositiveIntegerField(_("Mouchard KM"), blank=True, null=True)
    fuel_quantity = models.DecimalField(_("Quantitée en Litres"), max_digits=5, decimal_places=1)
    fuel_unit_price = models.DecimalField(_("Prix en DH"), max_digits=6, decimal_places=2)
    note = models.CharField(_("Remarque"), max_length=255, blank=True, null=True)
    created_at = models.DateTimeField(_("Created at"), auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(_("Updated at"), auto_now=True)
    is_active = models.BooleanField(default=True)

    @property
    def total_price(self):
        total_price = self.fuel_quantity * self.fuel_unit_price
        return total_price

    class Meta:
        ordering = ["gaz_station", "-created_at"]

    def __str__(self):
        return self.vehicle.serie

Я хочу использовать CBV для получения расстояния между каждыми двумя заправками для одного и того же автомобиля, чтобы я мог рассчитать расход топлива на километр. Есть ли способ сделать это?
ОТРЕДАКТИРОВАНО:
Я хочу возвращать при каждой заправке расход топлива на км, используя предыдущую заправку.

В ваших представлениях вы можете создать функцию представления, которая извлекает два объекта заправки, затем вы можете взять разницу и использовать ее в качестве контекста ваших шаблонов. Затем вы можете получить к ней доступ в шаблоне, используя любое название, в данном примере мы просто использовали то же имя, что и переменная "difference".

from myapp.models import Refuel 
from django.template import loader
from django.shortcuts import render
from django.http import HttpResponse


def odometer_difference(request):
    # get the two refuel objects with the odometer readings you needed to compare 
    refuel_1 = Refuel.objects.filter('your_filter') 
    refuel_2 = Refuel.objects.filter('your_filter')

    #define template 
    template = loader.get_template('my_template.html')
    
    difference = refuel_2.odometer_reading - refuel_1.odometer_reading

    context = { 'difference':difference} 

    return HttpResponse(template.render(context, request)) 

Вы можете использовать Window функции, использующие Lag для получения значения предыдущего ряда следующим образом:

from django.db.models import Window
from django.db.models.functions import Lag

last_odometer_reading = Window(
    expression=Lag('odometer_reading', default=0),
    partition_by=F('vehicle')
    order_by=F('created_at').asc(),
)

Refuel.objects.annotate(
    last_odometer_reading=last_odometer_reading
).annotate(
    odometer_difference=F('odometer_reading') - F('last_odometer_reading')
)

В каждой строке заправки будет указано последнее показание одометра (на основе заправки того же автомобиля), а также будет указана разница между текущим и последним показаниями.

Я использую form_valid **RefuelCreatView** при валидации новой записи, чтобы получить самые старые данные, выполнить расчет и сохранить RefuelConsumption Model.

class RefuelCreationView(LoginRequiredMixin, CreateView):
    model = Refuel
    form_class = RefuelCreationForm
    template_name = "refuel/refuel_form.html"
    success_url = reverse_lazy("refuel:controlor-refuel-list")

    def form_valid(self, form):
        form.instance.user_id = self.request.user.id
        form.instance.gaz_station = GazStation.objects.get(Controlor_id=self.request.user.id)
        old_refuel_data = Refuel.objects.order_by().distinct("vehicle")
        for refuel in old_refuel_data:
            if refuel.vehicle == form.instance.vehicle and form.instance.odometer_reading:
                consumption = (refuel.fuel_quantity / (form.instance.odometer_reading - refuel.odometer_reading)) * 100
                FuelConsumption.objects.create(
                    vehicle=refuel.vehicle,
                    gaz_station=form.instance.gaz_station,
                    Controlor_id=self.request.user,
                    driver=refuel.vehicle.driver,
                    consumption=consumption,
                    is_active=True,
                )
            elif refuel.vehicle == form.instance.vehicle and form.instance.snitch:
                consumption = (refuel.fuel_quantity / (form.instance.snitch - refuel.snitch)) * 100
                FuelConsumption.objects.create(
                    vehicle=refuel.vehicle,
                    gaz_station=form.instance.gaz_station,
                    Controlor_id=self.request.user,
                    driver=refuel.vehicle.driver,
                    consumption=consumption,
                    is_active=True,
                )
        return super().form_valid(form)

    def get_queryset(self, *args, **kwargs):
        return Refuel.objects.select_related("vehicle__gaz_station__Controlor_id").filter(
            vehicle__gaz_station__Controlor_id=self.request.user
        )

и это работает очень хорошо. Я не знаю, соблюдает ли это лучшие практики программирования или нет, я открыт для любых советов.

Вернуться на верх