get_or_create не работает для unique_together для десятичных чисел - PullRequest
3 голосов
/ 13 февраля 2020

У меня есть следующая модель:

class LocationPoint(models.Model):
    latitude = models.DecimalField(max_digits=9, decimal_places=6)
    longitude = models.DecimalField(max_digits=9, decimal_places=6)

    class Meta:
        unique_together = (
            ('latitude', 'longitude',),
        )

Interactor:

class GetOrCreateLocationPoint(object):

    def exec(self, latitude: Decimal, longitude: Decimal) -> LocationPoint:
        point, _ = LocationPoint.objects.get_or_create(
            latitude=latitude,
            longitude=longitude,

            defaults={
                'latitude': latitude,
                'longitude': longitude,
            },
        )

        return point

И проверка:

class GetOrCreateLocationPointTest(TestCase): # from django.test import TestCase
    __get_or_create_location_point: GetOrCreateLocationPoint

    def setUp(self) -> None:
        self.__get_or_create_location_point = GetOrCreateLocationPoint()

    def test_create_duplicate(self):
        point1 = self.__get_or_create_location_point.exec(Decimal(10.5), Decimal(5.01))
        self.__get_or_create_location_point.exec(Decimal(13.4), Decimal(1.5343))
        point3 = self.__get_or_create_location_point.exec(Decimal(10.5), Decimal(5.01))

        self.assertEqual(point1.pk, point3.pk)

При выполнении point3 = self.__get_or_create_location_point.exec(Decimal(10.5), Decimal(5.01)) я получаю ошибку :

django.db.utils.IntegrityError: duplicate key value violates unique constraint "geo_locationpoint_latitude_longitude_08fb2a82_uniq"
DETAIL:  Key (latitude, longitude)=(10.500000, 5.010000) already exists.

Однако, если в отладчике я вижу, что self.model.DoesNotExist выбрасывается (и обрабатывается) в get_or_create, значит, он не находит существующую строку.

Что не так?

Django 3.0.3, PostgreSQL 12.

1 Ответ

1 голос
/ 13 февраля 2020

Что ж, похоже, он не работает из-за использования чисел с плавающей точкой в ​​конструкторах Decimal ...

Замена чисел с плавающей точкой на строковое представление решает проблему:

    def test_create_duplicate(self):
        point1 = self.__get_or_create_location_point.exec(Decimal('10.5'), Decimal('5.01'))
        self.__get_or_create_location_point.exec(Decimal('13.4'), Decimal('1.5343'))
        point3 = self.__get_or_create_location_point.exec(Decimal('10.5'), Decimal('5.01'))

        self.assertEqual(point1.pk, point3.pk)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...