Пользовательский метод сохранения в модели Django - PullRequest
2 голосов
/ 02 июня 2019

Я написал собственный метод сохранения для модели, чтобы предотвратить сохранение недопустимых данных, но когда я хочу обновить объект через admin (просто для изменения некоторых свойств), я получаю ошибку подтверждения

моя модель:

class Segment(CoreModel):
    departure = models.ForeignKey(Place, on_delete=models.CASCADE, limit_choices_to=limit_choices_segment,
                                  related_name='departures')
    destination = models.ForeignKey(Place, on_delete=models.CASCADE, limit_choices_to=limit_choices_segment,
                                    related_name='arrivals')
    distance = models.FloatField(help_text='Distance between places in "km"!', null=True, blank=True,
                                 validators=[property_positive_value])
    duration = models.FloatField(help_text='Transfer duration (hours)', null=True, blank=True,
                                 validators=[property_positive_value])
    cost = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True,
                               help_text='Price for a transfer! Currency: "UAH"!',
                               validators=[property_positive_value])
    route = models.ForeignKey(Route, on_delete=models.CASCADE, related_name='segments')

    def __str__(self):
        return '{}-{}'.format(self.departure, self.destination)

    def save(self, *args, **kwargs):
        assert self.departure.role not in (Place.DISTRICT, Place.REGION), (
            "Departure couldn't be Region or District")
        assert self.destination.role not in (Place.DISTRICT, Place.REGION), (
            "Destination couldn't be Region orDistrict")
        assert self.destination != self.departure, "Departure couldn't be equal to Destination"
        assert self.route.segment_validate(departure=self.departure, destination=self.destination), (
            'Impossible to add the segment, please check the route!')

        if self.distance is not None:
            assert self.distance > 0, "Distance couldn't be less or equal to '0'!"
        if self.duration is not None:
            assert self.duration > 0, "Duration couldn't be less or equal to '0'!"
        if self.cost is not None:
            assert self.cost > 0, "Cost couldn't be less or equal to '0'!"
        super(Segment, self).save(*args, **kwargs)

метод проверки:

    def segment_validate(self, departure, destination):
        segments = self.segments.all()
        if segments:
            for segmnet in segments:
                same_departure = segmnet.departure == departure
                same_destination = segmnet.destination == destination
                if ((same_departure and same_destination) or
                        same_departure or same_destination):
                    return False
            if segments.latest('created').destination != departure:
                return False
        return True

ошибка здесь:

assert self.route.segment_validate(departure=self.departure, destination=self.destination), (
            'Impossible to add the segment, please check the route!')

но я не изменился departure и destination Не могли бы вы помочь мне избежать этой ошибки?

1 Ответ

0 голосов
/ 02 июня 2019

Причина, по которой это является проблемой, заключается в том, что если вы уже сохранили сегмент, и теперь вы спрашиваете, есть ли в базе данных сегмент с таким же department или destination. Если вы не обновили department из destination, то, конечно, есть: этот конкретный сегмент.

Мы можем исключить наш segment из него, если он существует, с:

from django.db.models import Q

def segment_validate(self, departure_pk, destination_pk, segment_pk):
    segments = self.segments.<b>exclude(pk=segment_pk)</b>
    if not segments.filter(
          Q(departure_id=departure_pk) |
          Q(destination_id=destination_pk)
      ).exists():
        return False
    if segment_pk is None:
        return segments.latest('created').destination_id != departure_pk
    return True

Таким образом, мы проверяем это с помощью:

assert self.route.segment_validate(<b>self.departure_id, self.destination_id, self.pk</b>), ('Impossible to add the segment, please check the route!')
...