Skip to content

Commit fc9b55e

Browse files
Sultpre-commit-ci[bot]jeking3
authored
Issue 720 no db indices (#782)
* implemented a register setting that allows you to drop db_index on history models, tests are also added * updated text files as required by contributing * ran make format Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jim King <[email protected]>
1 parent b443bd7 commit fc9b55e

File tree

6 files changed

+92
-0
lines changed

6 files changed

+92
-0
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Authors
4848
- Grzegorz Bialy
4949
- Guillermo Eijo (`guilleijo <https://github.com/guilleijo>`_)
5050
- Hamish Downer
51+
- Hans de Jong (`sult <https://github.com/sult>`_)
5152
- Hanyin Zhang
5253
- Hernan Esteves (`sevetseh28 <https://github.com/sevetseh28>`_)
5354
- Hielke Walinga (`hwalinga <https://github.com/hwalinga>`_)

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Full list of changes:
3030
- Dropped support for Python 3.6, which reached end-of-life on 2021-12-23 (gh-946).
3131
- Fix bug with ``history.diff_against`` with non-editable fields (gh-923)
3232
- Dropped support for Django 3.1 (gh-952)
33+
- RecordModels now support a ``no_db_index`` setting, to drop indices in historical models, default stays the same (gh-720)
3334

3435
3.0.0 (2021-04-16)
3536
------------------

docs/historical_model.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,31 @@ compatibility; it is more correct for a ``FileField`` to be converted to a
419419
420420
SIMPLE_HISTORY_FILEFIELD_TO_CHARFIELD = True
421421
422+
423+
Drop Database Indices
424+
--------------------------------
425+
426+
It is possible to use the parameter ``no_db_index`` to choose which fields
427+
that will not create a database index.
428+
429+
For example, if you have the model:
430+
431+
.. code-block:: python
432+
433+
class PollWithExcludeFields(models.Model):
434+
question = models.CharField(max_length=200, db_index=True)
435+
436+
437+
438+
And you don't want to create database index for ``question``, it is necessary to update the model to:
439+
440+
.. code-block:: python
441+
442+
class PollWithExcludeFields(models.Model):
443+
question = models.CharField(max_length=200, db_index=True)
444+
445+
history = HistoricalRecords(no_db_index=['question'])
446+
447+
448+
By default, django-simple-history keeps all indices. and even forces them on unique fields and relations.
449+
WARNING: This will drop performance on historical lookups

simple_history/models.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ def __init__(
8080
related_name=None,
8181
use_base_model_db=False,
8282
user_db_constraint=True,
83+
no_db_index=list(),
8384
excluded_field_kwargs=None,
8485
):
8586
self.user_set_verbose_name = verbose_name
@@ -101,6 +102,10 @@ def __init__(
101102
self.related_name = related_name
102103
self.use_base_model_db = use_base_model_db
103104

105+
if isinstance(no_db_index, str):
106+
no_db_index = [no_db_index]
107+
self.no_db_index = no_db_index
108+
104109
if excluded_fields is None:
105110
excluded_fields = []
106111
self.excluded_fields = excluded_fields
@@ -305,6 +310,11 @@ def copy_fields(self, model):
305310
field.name = old_field.name
306311
else:
307312
transform_field(field)
313+
314+
# drop db index
315+
if field.name in self.no_db_index:
316+
field.db_index = False
317+
308318
fields[field.name] = field
309319
return fields
310320

simple_history/tests/models.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,3 +770,21 @@ class ModelWithExcludedManyToMany(models.Model):
770770
name = models.CharField(max_length=15, unique=True)
771771
other = models.ManyToManyField(ManyToManyModelOther)
772772
history = HistoricalRecords(excluded_fields=["other"])
773+
774+
775+
class ModelWithSingleNoDBIndexUnique(models.Model):
776+
name = models.CharField(max_length=15, unique=True, db_index=True)
777+
name_keeps_index = models.CharField(max_length=15, unique=True, db_index=True)
778+
history = HistoricalRecords(no_db_index="name")
779+
780+
781+
class ModelWithMultipleNoDBIndex(models.Model):
782+
name = models.CharField(max_length=15, db_index=True)
783+
name_keeps_index = models.CharField(max_length=15, db_index=True)
784+
fk = models.ForeignKey(
785+
"Library", on_delete=models.CASCADE, null=True, related_name="+"
786+
)
787+
fk_keeps_index = models.ForeignKey(
788+
"Library", on_delete=models.CASCADE, null=True, related_name="+"
789+
)
790+
history = HistoricalRecords(no_db_index=["name", "fk", "other"])

simple_history/tests/tests/test_models.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
ModelWithFkToModelWithHistoryUsingBaseModelDb,
7171
ModelWithHistoryInDifferentDb,
7272
ModelWithHistoryUsingBaseModelDb,
73+
ModelWithMultipleNoDBIndex,
74+
ModelWithSingleNoDBIndexUnique,
7375
MultiOneToOne,
7476
MyOverrideModelNameRegisterMethod1,
7577
OverrideModelNameAsCallable,
@@ -1822,3 +1824,35 @@ def test_history_model_saved_in_separate_db_on_delete(self):
18221824
self.assertEqual(
18231825
0, ModelWithHistoryInDifferentDb.objects.using("other").count()
18241826
)
1827+
1828+
1829+
class ModelWithMultipleNoDBIndexTest(TestCase):
1830+
def setUp(self):
1831+
self.model = ModelWithMultipleNoDBIndex
1832+
self.history_model = self.model.history.model
1833+
1834+
def test_field_indices(self):
1835+
for field in ["name", "fk"]:
1836+
# dropped index
1837+
self.assertTrue(self.model._meta.get_field(field).db_index)
1838+
self.assertFalse(self.history_model._meta.get_field(field).db_index)
1839+
1840+
# keeps index
1841+
keeps_index = "%s_keeps_index" % field
1842+
self.assertTrue(self.model._meta.get_field(keeps_index).db_index)
1843+
self.assertTrue(self.history_model._meta.get_field(keeps_index).db_index)
1844+
1845+
1846+
class ModelWithSingleNoDBIndexUniqueTest(TestCase):
1847+
def setUp(self):
1848+
self.model = ModelWithSingleNoDBIndexUnique
1849+
self.history_model = self.model.history.model
1850+
1851+
def test_unique_field_index(self):
1852+
# Ending up with deferred fields (dont know why), using work around
1853+
self.assertTrue(self.model._meta.get_field("name").db_index)
1854+
self.assertFalse(self.history_model._meta.get_field("name").db_index)
1855+
1856+
# keeps index
1857+
self.assertTrue(self.model._meta.get_field("name_keeps_index").db_index)
1858+
self.assertTrue(self.history_model._meta.get_field("name_keeps_index").db_index)

0 commit comments

Comments
 (0)