@@ -128,3 +128,275 @@ Using ``--nomigrations`` will disable Django migrations and create the database
128
128
by inspecting all models. It may be faster when there are several migrations to
129
129
run in the database setup. You can use ``--migrations `` to force running
130
130
migrations in case ``--nomigrations `` is used, e.g. in ``setup.cfg ``.
131
+
132
+ .. _advanced-database-configuration :
133
+
134
+ Advanced database configuration
135
+ -------------------------------
136
+
137
+ pytest-django provides options to customize the way database is configured. The
138
+ default database construction mostly follows Django's own test runner. You can
139
+ however influence all parts of the database setup process to make it fit in
140
+ projects with special requirements.
141
+
142
+ This section assumes some familiary with the Django test runner, Django
143
+ database creation and pytest fixtures.
144
+
145
+ Fixtures
146
+ ########
147
+
148
+ There are some fixtures which will let you change the way the database is
149
+ configured in your own project. These fixtures can be overridden in your own
150
+ project by specifying a fixture with the same name and scope in ``conftest.py ``.
151
+
152
+ .. admonition :: Use the pytest-django source code
153
+
154
+ The default implementation of these fixtures can be found in
155
+ `fixtures.py <https://github.com/pytest-dev/pytest-django/blob/master/pytest_django/fixtures.py >`_.
156
+
157
+ The code is relatively short and straightforward and can provide a
158
+ starting point when you need to customize database setup in your own
159
+ project.
160
+
161
+
162
+ django_db_setup
163
+ """""""""""""""
164
+
165
+ .. fixture :: django_db_setup
166
+
167
+ This is the top-level fixture that ensures that the test databases are created
168
+ and available. This fixture is session scoped (it will be run once per test
169
+ session) and is responsible for making sure the test database is available for tests
170
+ that need it.
171
+
172
+ The default implementation creates the test database by applying migrations and removes
173
+ databases after the test run.
174
+
175
+ You can override this fixture in your own ``conftest.py `` to customize how test
176
+ databases are constructed.
177
+
178
+ django_db_modify_db_settings
179
+ """"""""""""""""""""""""""""
180
+
181
+ .. fixture :: django_db_modify_db_settings
182
+
183
+ This fixture allows modifying `django.conf.settings.DATABASES ` just before the
184
+ databases are configured.
185
+
186
+ If you need to customize the location of your test database, this is the
187
+ fixture you want to override.
188
+
189
+ The default implementation of this fixture requests the
190
+ :fixture: `django_db_modify_db_settings_xdist_suffix ` to provide compatibility
191
+ with pytest-xdist.
192
+
193
+ This fixture is by default requested from :fixture: `django_db_setup `.
194
+
195
+ django_db_modify_db_settings_xdist_suffix
196
+ """""""""""""""""""""""""""""""""""""""""
197
+
198
+ .. fixture :: django_db_modify_db_settings_xdist_suffix
199
+
200
+ Requesting this fixture will add a suffix to the database name when the tests
201
+ are run via pytest-xdist.
202
+
203
+ This fixture is by default requsted from
204
+ :fixture: `django_db_modify_db_settings_xdist_suffix `.
205
+
206
+ django_db_use_migrations
207
+ """"""""""""""""""""""""
208
+
209
+ .. fixture :: django_db_use_migrations
210
+
211
+ Returns whether or not to use migrations to create the test
212
+ databases.
213
+
214
+ The default implementation returns the value of the
215
+ ``--migrations ``/``--nomigrations `` command line options.
216
+
217
+ This fixture is by default requested from :fixture: `django_db_setup `.
218
+
219
+ django_db_keepdb
220
+ """"""""""""""""
221
+
222
+ .. fixture :: django_db_keepdb
223
+
224
+ Returns whether or not to re-use an existing database and to keep it after the
225
+ test run.
226
+
227
+ The default implementation handles the ``--reuse-db `` and ``--create-db ``
228
+ command line options.
229
+
230
+ This fixture is by default requested from :fixture: `django_db_setup `.
231
+
232
+ django_db_blocker
233
+ """""""""""""""""
234
+
235
+ .. fixture :: django_db_blocker
236
+
237
+ .. warning ::
238
+ It does not manage transactions and changes made to the database will not
239
+ be automatically restored. Using the :func: `pytest.mark.django_db ` marker
240
+ or :fixture: `db ` fixture, which wraps database changes in a transaction and
241
+ restores the state is generally the thing you want in tests. This marker
242
+ can be used when you are trying to influence the way the database is
243
+ configured.
244
+
245
+ Database access is by default not allowed. ``django_db_blocker `` is the object
246
+ which can allow specific code paths to have access to the database. This
247
+ fixture is used internally to implement the ``db `` fixture.
248
+
249
+
250
+ :fixture: `django_db_blocker ` can be used as a context manager to enable database
251
+ access for the specified block::
252
+
253
+ @pytest.fixture
254
+ def myfixture(django_db_blocker):
255
+ with django_db_blocker:
256
+ ... # modify something in the database
257
+
258
+ You can also manage the access manually via these methods:
259
+
260
+ .. py :method :: django_db_blocker.enable_database_access()
261
+
262
+ Enable database access. Should be followed by a call to
263
+ :func: `~django_db_blocker.restore_previous_access `.
264
+
265
+ .. py :method :: django_db_blocker.disable_database_access()
266
+
267
+ Disable database access. Should be followed by a call to
268
+ :func: `~django_db_blocker.restore_previous_access `.
269
+
270
+ .. py :function :: django_db_blocker.restore_previous_access()
271
+
272
+ Restore the previous state of the database blocking.
273
+
274
+ Examples
275
+ ########
276
+
277
+ Using a template database for tests
278
+ """""""""""""""""""""""""""""""""""
279
+
280
+ This example shows how a pre-created PostgreSQL source database can be copied
281
+ and used for tests.
282
+
283
+ Put this into ``conftest.py ``::
284
+
285
+ import pytest
286
+ from django.db import connections
287
+
288
+ import psycopg2
289
+ from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
290
+
291
+
292
+ def run_sql(sql):
293
+ conn = psycopg2.connect(database='postgres')
294
+ conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
295
+ cur = conn.cursor()
296
+ cur.execute(sql)
297
+ conn.close()
298
+
299
+
300
+ @pytest.yield_fixture(scope='session')
301
+ def django_db_setup():
302
+ from django.conf import settings
303
+
304
+ settings.DATABASES['default']['NAME'] = 'the_copied_db'
305
+
306
+ run_sql('DROP DATABASE IF EXISTS the_copied_db')
307
+ run_sql('CREATE DATABASE the_copied_db TEMPLATE the_source_db')
308
+
309
+ yield
310
+
311
+ for connection in connections.all():
312
+ connection.close()
313
+
314
+ run_sql('DROP DATABASE the_copied_db')
315
+
316
+
317
+ Using an existing, external database for tests
318
+ """"""""""""""""""""""""""""""""""""""""""""""
319
+
320
+ This example shows how you can connect to an existing database and use it for
321
+ your tests. This example is trivial, you just need to disable all of
322
+ pytest-django and Django's test database creation and point to the existing
323
+ database. This is achieved by simply implementing a no-op
324
+ :fixture: `django_db_setup ` fixture.
325
+
326
+ Put this into ``conftest.py ``::
327
+
328
+ import pytest
329
+
330
+
331
+ @pytest.fixture(scope='session')
332
+ def django_db_setup():
333
+ settings.DATABASES['default'] = {
334
+ 'ENGINE': 'django.db.backends.mysql',
335
+ 'HOST': 'db.example.com',
336
+ 'NAME': 'external_db',
337
+ }
338
+
339
+
340
+ Populate the database with initial test data
341
+ """"""""""""""""""""""""""""""""""""""""""""
342
+
343
+ This example shows how you can populate the test database with test data. The
344
+ test data will be saved in the database, i.e. it will not just be part of a
345
+ transactions. This example uses Django's fixture loading mechanism, but it can
346
+ be replaced with any way of loading data into the database.
347
+
348
+ Notice that :fixture: `django_db_setup ` is in the argument list. This may look
349
+ odd at first, but it will make sure that the sure that the original
350
+ pytest-django fixture is used to create the test database. When
351
+ ``call_command `` is invoked, the test database is already prepared and
352
+ configured.
353
+
354
+ Put this in ``conftest.py ``::
355
+
356
+ import pytest
357
+
358
+ from django.core.management import call_command
359
+
360
+ @pytest.fixture(scope='session')
361
+ def django_db_setup(django_db_setup, django_db_blocker):
362
+ with django_db_blocker:
363
+ call_command('loaddata', 'your_data_fixture.json')
364
+
365
+ Use the same database for all xdist processes
366
+ """""""""""""""""""""""""""""""""""""""""""""
367
+
368
+ By default, each xdist process gets its own database to run tests on. This is
369
+ needed to have transactional tests that does not interfere with eachother.
370
+
371
+ If you instead want your tests to use the same database, override the
372
+ :fixture: `django_db_modify_db_settings ` to not do anything. Put this in
373
+ ``conftest.py ``::
374
+
375
+ import pytest
376
+
377
+
378
+ @pytest.fixture(scope='session')
379
+ def django_db_modify_db_settings():
380
+ pass
381
+
382
+ Randomize database sequences
383
+ """"""""""""""""""""""""""""
384
+
385
+ You can customize the test database after it has been created by extending the
386
+ :fixture: `django_db_setup ` fixture. This example shows how to give a PostgreSQL
387
+ sequence a random starting value. This can be used to detect and prevent
388
+ primary key id's from being hard-coded in tests.
389
+
390
+ Put this in ``conftest.py ``::
391
+
392
+ import random
393
+ import pytest
394
+ from django.db import connection
395
+
396
+
397
+ @pytest.fixture(scope='session')
398
+ def django_db_setup(django_db_setup, django_db_blocker):
399
+ with django_db_blocker:
400
+ cur = connection.cursor()
401
+ cur.execute('ALTER SEQUENCE app_model_id_seq RESTART WITH %s;',
402
+ [random.randint(10000, 20000)])
0 commit comments