question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multiple fields not supported in django_get_or_create

See original GitHub issue

I am currently using factory_boy with faker to generate test data for my django application. The model that I am currently testing looks like the following;

class Thing(models.Model):
    name = models.CharField(max_length=50)
    code = models.CharField(max_length=20, unique=True)
    short_code = models.CharField(max_length=5, unique=True)

My factory looks like this;

class ThingFactory(factory.django.DjangoModelFactory)
    class Meta:
        model = app.models.Thing
        django_get_or_create = ('code', 'short_code')
    name = factory.lazy_attribute(lambda x: faker.company())
    code = factory.sequence(lambda n: 'thing-code-%05d' % n)
    short_code = factory.sequence(lambda n: '%05d' % n)

and my test to verify that this is functioning properly is;

def test_thing_code(self):
    ThingFactory.create(code="test")
    things = Thing.objects.all()
    assert_equal(len(things), 1)
    thing = Thing.objects.get(code="test")
    ThingFactory.create(short_code=thing.short_code)
    ThingFactory.create(code="test")
    things = Clinic.objects.all()
    assert_equal(len(things), 1)

The expected behaviour of this test is that when I run a create using the existing short_code, I should instead get the same object that already exists. Additionally, when I attempt to create a new object using the same code as the first line, I should also get the same object. When I execute this, I receive the following error message:

test_thing_code ... ERROR

======================================================================
ERROR: test_thing_code
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/app/test/tests.py", line 109, in test_thing_code
    ThingFactory.create(short_code=thing.short_code)
  File "/home/factory_boy/factory/base.py", line 559, in create
    return cls._generate(True, attrs)
  File "/home/factory_boy/factory/django.py", line 288, in wrapped_generate
    return generate_method(*args, **kwargs)
  File "/home/factory_boy/factory/base.py", line 484, in _generate
    obj = cls._prepare(create, **attrs)
  File "/home/factory_boy/factory/base.py", line 459, in _prepare
    return cls._create(model_class, *args, **kwargs)
  File "/home/factory_boy/factory/django.py", line 147, in _create
    return cls._get_or_create(model_class, *args, **kwargs)
  File "/home/factory_boy/factory/django.py", line 138, in _get_or_create
    obj, _created = manager.get_or_create(*args, **key_fields)
  File "/home/django/django/db/models/manager.py", line 134, in get_or_create
    return self.get_query_set().get_or_create(**kwargs)
  File "/home/django/django/db/models/query.py", line 452, in get_or_create
    obj.save(force_insert=True, using=self.db)
  File "/home/django/django/utils/functional.py", line 11, in _curried
    return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
  File "/home/app/models.py", line 415, in capture_user_on_save
    output = old_save(self, *args, **kwargs)
  File "/home/app/models.py", line 264, in save
    super(Thing, self).save(*args, **kwargs)
  File "/home/django/django/db/models/base.py", line 463, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/home/django/django/db/models/base.py", line 551, in save_base
    result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
  File "/home/django/django/db/models/manager.py", line 203, in _insert
    return insert_query(self.model, objs, fields, **kwargs)
  File "/home/django/django/db/models/query.py", line 1593, in insert_query
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/home/django/django/db/models/sql/compiler.py", line 912, in execute_sql
    cursor.execute(sql, params)
  File "/home/django/django/db/backends/postgresql_psycopg2/base.py", line 52, in execute
    return self.cursor.execute(query, args)
IntegrityError: duplicate key value violates unique constraint "app_thing_short_code_key"
DETAIL:  Key (short_code)=(000) already exists.

This error was received using factory_boy 2.5.2 and Django 1.4.20 final

If I change the order in the django_get_or_create attribute, whichever one is listed second is the test that causes the database error.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:4
  • Comments:11 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
Aprechecommented, Oct 11, 2018

I just recently started using factory boy and also encountered this issue. It’s basically impossible to create objects reliably if there is more than one unique field on the model. Most of my models have more than one unique in them. I don’t even want to know what kind of troubles I would get into if I had a unique_together constraint. Sad to see this issue is years old with little to no progress.

1reaction
webynetercommented, Nov 13, 2018

Any updates? It’s really crucial for the majority of users to have it implemented, myself included.

Read more comments on GitHub >

github_iconTop Results From Across the Web

MultipleObjectsReturned with get_or_create - django
I'm not certain about the integrity of the database I'm cloning, but even if there are multiple identical objects in it, when I...
Read more >
#27070 (Support for `Q` objects in `get_or_create` and ...
When OR ing Q objects, if the lookup fails, and those fields are not specified in defaults , we have undefined values for...
Read more >
problems with get_or_create - Google Groups
hi,. I have a model like this: name - unique slno - not null mode - not null. If the instance does not...
Read more >
How to use get_or_create in Django? - The TLDR Tech
This is one of those two query one command ORM methods. ... If the fields used in the keyword arguments do not have...
Read more >
Misleading exception from changing get_or_create behaviour ...
If any field given with django_get_or_create in a factory class, ... with presented with Test django get or create multiple fields #345.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found