Django Models - Как определить, что запись обновляется, а не вставляется новая?

Для одной из моих моделей, которую я использую, есть некоторая условная логика, которая происходит, и часть того, что мне нужно знать, если запись делается в первый раз, или если это обновление существующей модели. Моя модель приведена ниже, далее я приведу пример того, что мне нужно.

Модель отгрузки

class Shipment(models.Model):
    CARRIER_CHOICES = [
        ('GW', 'Greatwide'),
        ('SM', 'Sample'),
    ]
    dateTendered = models.DateField(default=date.today)
    loadNumber = models.CharField(max_length=50)
    masterBolNumber = models.CharField(max_length=50)
    carrier = models.CharField(max_length=100, blank=True, choices=CARRIER_CHOICES, default='GW')
    destinationCity = models.CharField(max_length=70)
    destinationState = models.CharField(max_length=50)
    rateLineHaul = models.DecimalField(max_digits=15, decimal_places=2)
    rateFSC = models.DecimalField(max_digits=15, decimal_places=2)
    rateExtras = models.DecimalField(max_digits=15, decimal_places=2, default=0.00)
    rateTotal = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True, default=0.00)
    loadDelivered = models.BooleanField(default=False)
    customCarrierRate = models.BooleanField(default=False)
    deliveryDate = models.DateField(null=True, blank=True)
    deliveryTime = models.TimeField(null=True, blank=True)
    driverName = models.CharField(max_length=70, null=True, blank=True)
    driverCell = models.CharField(max_length=70, null=True, blank=True)
    rateTotalCarrier = models.DecimalField(max_digits=15, decimal_places=2, null=True, default=0)
    shipmentMargin = models.DecimalField(max_digits=15, decimal_places=2, null=True, blank=True)
    shipmentMarginPercentage = models.DecimalField(max_digits=15, decimal_places=3, null=True, blank=True)
    trailer = models.ForeignKey(Trailer, on_delete=models.PROTECT, blank=True, null=True)
    id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)

Вот несколько примеров того, почему мне нужно различать обновление и вставку.

Possible Scenarios When Adding a Shipment
    a. Only required fields are entered. Then the following happens
        1a. Calculate rateTotal
        1b. Calculate rateTotalCarrier
        1c. Calculate Shipment Margin
        1d. Calculate Shipment Margin Percentage
    b. Required Fields + customCarrierRate is checked 
        2a. Calculate rateTotal 
        2b. Set rateTotalCarrier = 0.00 
        2c. Don't calculate any Margin 
    c. Required Fields + Value entered in rateTotalCarrier 
        3a. Set customCarrierRate to True
        3b. Calculate rateTotal
        3c. Calculate Shipment Margin
        3d. Calculate Shipment Margin Percentage
    d. Required Fields + Trailer Selected 
        4a. Follow the steps in scenario a
        4b. Save the shipment entry, then find the trailerTrip that matches the trailer Number, and update
            the trailer trip with the shipment load number.

Possible Scenarios When Editing a Shipment
    a. Carrier Rate is changed 
        1a. Set customCarrierRate to True 
        1b. Re-calculate Shipment Margin and Percentage. 
    b. Trailer Number is changed 
        2a. Before saving the entry, find the trailerTrip that matches the old trailer number, and update the trailer
            trip Shipment to NULL 
        2b. Save the shipment entry, then update the corresponding TrailerTrip
    c. Rate is changed 
        3a. Follow steps from scenario a above. 

Некоторые вычисления, которые производятся, выполняются вспомогательными функциями, эти функции приведены ниже.

calcRate()

# Used by Shipment Model
def calcRate(shipmentId):
    shipment = Shipment.objects.get(id=shipmentId)
    shipment.rateTotal = shipment.rateLineHaul + shipment.rateFSC + shipment.rateExtras
    if shipment.customCarrierRate is False:
        if checkRate(shipment.destinationState) is False:
            shipment.rateTotalCarrier = ((shipment.rateLineHaul * Decimal(
                0.8)) + shipment.rateFSC + shipment.rateExtras) - Decimal(250)
        else:
            rateList = checkRate(shipment.destinationState)
            miles = shipment.rateLineHaul / Decimal(rateList[1])
            linehaul = Decimal(miles) * Decimal(rateList[2])
            shipment.rateTotalCarrier = ((linehaul * Decimal(0.8)) + shipment.rateFSC + shipment.rateExtras) - Decimal(
                250)
    shipment.save()

calcShipmentMargin()

# Used by Shipment Model
def calcShipmentMargin(shipmentId):
    shipment = Shipment.objects.get(id=shipmentId)
    shipment.shipmentMargin = shipment.rateTotal - shipment.rateTotalCarrier
    shipment.shipmentMarginPercentage = (shipment.shipmentMargin / shipment.rateTotal) * 100
    shipment.save()

updateTrailerTrip()

# Used by Shipment Model
def updateTrailerTrip(shipmentId, trailer):
    shipment = Shipment.objects.get(id=shipmentId)
    trailerTrip = TrailerTrip.objects.get(trailer=trailer)
    trailerTrip.shipment = shipment
    trailerTrip.save()

В своих моделях вы можете переписать функцию save :

def save(self, *args, **kwargs):
    created = self._state.adding is True
    if created:
       # Do your things on created element
    else:
       # Do your things on updated element
    super().save(*args, **kwargs)  # Call the "real" save() method.

При таком методе вам нужно будет отредактировать ваши функции следующим образом:

# Used by Shipment Model
def calcRate(self):
    self.rateTotal = self.rateLineHaul + self.rateFSC + self.rateExtras
    if self.customCarrierRate is False:
        if checkRate(self.destinationState) is False:
            self.rateTotalCarrier = ((self.rateLineHaul * Decimal(
                0.8)) + self.rateFSC + self.rateExtras) - Decimal(250)
        else:
            rateList = checkRate(self.destinationState)
            miles = self.rateLineHaul / Decimal(rateList[1])
            linehaul = Decimal(miles) * Decimal(rateList[2])
            self.rateTotalCarrier = ((linehaul * Decimal(0.8)) + shipment.rateFSC + shipment.rateExtras) - Decimal(
                250)

и сохранить будет

def save(self, *args, **kwargs):
    created = self._state.adding is True
    if created:
       self.calcRate()
    else:
       # Do your things on updated element
    super().save(*args, **kwargs)  # Call the "real" save() method.
Вернуться на верх