Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DjangoModelFactory.build hits the database #111

Closed
hannesstruss opened this issue Dec 2, 2013 · 3 comments
Closed

DjangoModelFactory.build hits the database #111

hannesstruss opened this issue Dec 2, 2013 · 3 comments

Comments

@hannesstruss
Copy link

given this constellation:

class MyModel(models.Model):
    name = models.CharField(max_length=100)

class ModelFactory(DjangoModelFactory):
    FACTORY_FOR = MyModel

    name = 'John Doe'

class MyTestCase(TestCase):
    def test_factory(self):
        ModelFactory.build()

The test case will hit the database when generating an ID for the model (Stacktrace when using py.test that detects database usage in tests: https://gist.github.com/hannesstruss/f60e038daa588318ea57 )

I would expect .build() to not touch the database at all, but to create in-memory/test-local objects only. As far as I remember that was also how it worked before all Django-specific code was moved to DjangoModelFactory.

If this is expected, sorry for missing the memo :) What would be the best practice then to share code between a factory that does and one that doesn't save the model?

I tested in 2.2.1/Django 1.6.

@rbarrois
Copy link
Member

rbarrois commented Dec 2, 2013

Hi,

That's a recurring issue I have with the "auto-next-sequence" code, which I haven't gotten to fix yet : it requires a big rewrite of some internals to pass the "build or create" context around.

The simplest way to solve this would be to override the _generate_next_sequence to always return "1".

@anler
Copy link

anler commented May 27, 2014

Hi, one problem with that solution is that I'm using sequence to disambiguate unique fields (eg: username) and returning the same value for the sequence raises IntegrityError for these fields.

The best solution I could come with is just maintaining a global counter since I don't care what value the sequence has but that is unique everytime and leaves the database untouched:

    _SEQUENCE = 1
    _SEQUENCE_LOCK = threading.Lock()
    ...
    @classmethod
    def _setup_next_sequence(cls):
        with cls._SEQUENCE_LOCK:
            cls._SEQUENCE += 1
        return cls._SEQUENCE

rbarrois added a commit that referenced this issue Nov 16, 2014
Related to issues #78, #92, #103, #111, #153, #170

The default value of all sequences is now 0; the automagic
``_setup_next_sequence`` behavior of Django/SQLAlchemy has been removed.

This feature's only goal was to allow the following scenario:

1. Run a Python script that uses MyFactory.create() a couple of times
   (with a unique field based on the sequence counter)
2. Run the same Python script a second time

Without the magical ``_setup_next_sequence``, the Sequence counter would be set
to 0 at the beginning of each script run, so both runs would generate objects
with the same values for the unique field ; thus conflicting and crashing.

The above behavior having only a very limited use and bringing various
issues (hitting the database on ``build()``, problems with non-integer
or composite primary key columns, ...), it has been removed.

It could still be emulated through custom ``_setup_next_sequence``
methods, or by calling ``MyFactory.reset_sequence()``.
@rbarrois
Copy link
Member

This issue has been fixed in 13d310f, and will be part of the 2.5.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants