Richard
Richard

Reputation: 65600

Django get_or_create trying to create row, throwing IntegrityError?

I'm working in Django 1.7 and Postgres, and using the ORM to create some new rows. I am using get_or_create as follows:

    p, created = Practice.objects.get_or_create(
        code=row[1],
        name=row[2],
        address1=row[3],
        address2=row[4],
        address3=row[5],
        address4=row[6],
        postcode=row[7]
    )

But when I try to run this I get:

django.db.utils.IntegrityError: duplicate key value violates unique constraint
DETAIL:  Key (code)=(A82057) already exists

What's this about? I thought the point of get_or_create was to only try to create new rows if they didn't already exist.

My model looks like this:

class Practice(TimeStampedModel):
    code = models.CharField(max_length=6, primary_key=True, db_index=True)
    name = models.CharField(max_length=200)
    address1 = models.CharField(max_length=200, null=True, blank=True)
    address2 = models.CharField(max_length=200, null=True, blank=True)
    address3 = models.CharField(max_length=200, null=True, blank=True)
    address4 = models.CharField(max_length=200, null=True, blank=True)
    postcode = models.CharField(max_length=9, null=True, blank=True)

def __str__(self):
    return self.name

class Meta:
    app_label = 'frontend'
    ordering = ['name']

Is it something to do with the fact that I've set a manual primary key? I can't see anything in the Django docs about this restriction.

Upvotes: 1

Views: 3077

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 600041

get_or_create attempts to do a get with all of the parameters you pass, not just the PK. So if there is an object with a matching PK but a different postcode, for example, the get will fail so a create will be attempted - but, since you have a manual PK, it will try to create a duplicate one using the data you have passed.

Generally speaking using a non-autoincrementing PK is a bad idea. But if you are just trying to look up against the PK only, use the defaults argument:

p, created = Practice.objects.get_or_create(
    code=row[1],
    defaults={
        'name': row[2],
        'address1': row[3],
        'address2': row[4],
        'address3': row[5],
        'address4': row[6],
        'postcode': row[7]
    })

Upvotes: 9

Related Questions