The Python Oracle

How do I fix django.db.utils.IntegrityError: duplicate key value violates unique constraint?

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Dreamlands

--

Chapters
00:00 How Do I Fix Django.Db.Utils.Integrityerror: Duplicate Key Value Violates Unique Constraint?
02:17 Answer 1 Score 2
02:59 Accepted Answer Score 3
04:02 Thank you

--

Full question
https://stackoverflow.com/questions/2343...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #mysql #django #postgresql #psycopg2

#avk47



ACCEPTED ANSWER

Score 3


This answered my question.

_coordinates, coordinates_created = Coordinates.objects.get_or_create(            
    lat=Decimal(group[u'lat'])._rescale(-Coordinates.max_decimal_places, 'ROUND_HALF_EVEN'),
    lon=Decimal(group[u'lon'])._rescale(-Coordinates.max_decimal_places, 'ROUND_HALF_EVEN'),
    created_by=self._user,
    modified_by=self._user,         
)

The auto_now and auto_now_add were just fine. It turns out that all of my defaults are already defined on the Model.

The problem was that group[u'lat'] and group[u'lon'] were both cast as floats when I placed them in my dictionary. In contrast, lat and lon are both defined as DecimalFields().

When using MySQL I can compare these float values against the contents of the database just fine. However, when I use Postgres the get() portion of get_or_create() attempts to compare a Decimal value from the database with the the float values I was providing it. The types are interpreted more strongly, and the float will not be cast to a Decimal during the comparison.

In my debugger, I saw:

{Decimal}lat
{float}group[lat]

It would be nice if django could produce a clear error like TypeError: Can't compare Decimal with float.




ANSWER 2

Score 2


You missed defaults argument in the get_or_create call. Then, if there is no record in the db with the specified lat, lon, it will create a new record with the default lat, lon, which obviously are not autogenerated and you get the IntegrityError.

_coordinates, coordinates_created = Coordinates.objects.get_or_create(
    lat=round(group[u'lat'], Coordinates.max_decimal_places),
    lon=round(group[u'lon'], Coordinates.max_decimal_places),
    created_by=self._user,
    defaults=dict(
        lat=round(group[u'lat'], Coordinates.max_decimal_places),
        lon=round(group[u'lon'], Coordinates.max_decimal_places),
        created_by=self._user,
        modified_by=self._user,
    )
)

As the unique index consist of columns lat, lon and created_by (looking at the index name from the error), you should use all of them in the filters of get_or_create.