13

Thanks for taking time to read my question.

I have a django app with the following model:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    ...

class Visit(models.Model):
    profile = models.ForeignKey(UserProfile)
    date = models.DateField(auto_now_add=True, db_index=True)
    ip = models.IPAddressField()
    class Meta:
        unique_together = ('profile', 'date', 'ip')

In a view:

profile = get_object_or_404(Profile, pk = ...)
get, create = Visit.objects.get_or_create(profile=profile, date=now.date(), ip=request.META['REMOTE_ADDR'])
if create: DO SOMETHING

Everything works fine, except that the Postgres Logs are full with duplicate key errors:

2012-02-15 14:13:44 CET ERROR:  duplicate key value violates unique constraint "table_visit_profile_id_key"
2012-02-15 14:13:44 CET STATEMENT:  INSERT INTO "table_visit" ("profile_id", "date", "ip") VALUES (1111, E'2012-02-15', E'xx.xx.xxx.xxx') RETURNING "table_visit"."id"

Tried different solution e.g.

from django.db import transaction 
from django.db import IntegrityError

@transaction.commit_on_success
def my_get_or_create(prof, ip):    
    try:
        object = Visit.objects.create(profile=prof, date=datetime.now().date(), ip=ip)
    except IntegrityError:
        transaction.commit()
        object = Visit.objects.get(profile=prof, date=datetime.now().date(), ip=ip)
    return object

....

created = my_get_or_create(prof, request.META['REMOTE_ADDR'])
if created: DO SOMETHING

This only helps for MySQL? Does anyone know how to avaid the duplicate key value errors for postgres?

Barmi
  • 261
  • 2
  • 6

4 Answers4

12

Another possible reason for these errors in get_or_create() is data type mismatch in one of the search fields - for example passing False instead of None into a nullable field. The .get() inside .get_or_create() will not find it and Django will continue with new row creation - which will fail due to PostgreSQL constraints.

kravietz
  • 10,667
  • 2
  • 35
  • 27
  • 1
    Thanks for your answer :) – Barmi May 17 '16 at 08:18
  • Ended what would have otherwise been a morning-long headache for me. – alphazwest Dec 28 '20 at 14:31
  • I agree with you on this point, when you set query as: `obj, created = UserPermission.objects.get_or_create( user=user, boolean_field=boolean_field)` The boolean field is False, it will always try to create object and raise: `duplicate key value violates unique constraint` because you have defined `boolean_field=models.BooleanField(default=False)` – Tarek Kalaji Oct 22 '21 at 08:24
4

I had issues with get_or_create when using postgres. In the end I abandoned the boilerplate code for traditional:

try:
    jobInvite  = Invite.objects.get(sender=employer.user, job=job)
except Invite.DoesNotExist:
    jobInvite  = Invite(sender=employer.user, job=job)
    jobInvite.save()
# end try
MagicLAMP
  • 1,032
  • 11
  • 26
  • 8
    Although this solution will appear to be working on most sites, it will fail on heavy traffic sites where lots of concurrent requests are at work. – Simon Steinberger May 17 '16 at 08:20
1

Have you at some point had unique=True set on Visit's profile field?

It looks like there's been a unique constraint generated for postgres that's still in effect. "table_visit_profile_id_key" is what it's auto generated name would be, and naturally it would cause those errors if you're recording multiple visits for a user.

If this is the case, are you using South to manage your database changes? If you aren't, grab it!

0

PostgreSQL behaves somewhat differently in some subtle queries, which results in IntegrityError errors, especially after you switch to Django 1.6. Here's the solution - you need to add select_on_save option to each failing model:

class MyModel(models.Model):
     ...
     class Meta:
         select_on_save = True

It's documented here: Options.select_on_save

kravietz
  • 10,667
  • 2
  • 35
  • 27