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.