简体   繁体   中英

get_or_create fails for unique_together for decimals

I have the following model:

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

And test:

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)

I get an error while executing 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.

However, if in debugger I see that self.model.DoesNotExist is thrown (and handled) in get_or_create , so it does not find the existing row.

What's wrong?

Django 3.0.3, PostgreSQL 12.

Well, it seems to fail because of using floats in Decimal constructors…

Replacing floats with string representation resolved the issue:

    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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM