get_or_create 对于小数 unique_together 失败

get_or_create fails for unique_together for decimals

我有以下型号:

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',),
        )

互动者:

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.DoesNotExistget_or_create 中被抛出(并处理),那么它找不到现有的行。

怎么了?

Django 3.0.3,PostgreSQL 12.

好吧,它似乎失败了,因为在 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)