Skip to content

Commit dded689

Browse files
authored
Allow to exclude some fields from diff_against check (#680)
* [#674] Allow to exclude some fields from `diff_against` check * Add command test * Run make format command * Edit CHANGES.rst * Fix help message
1 parent 37e5244 commit dded689

File tree

7 files changed

+52
-3
lines changed

7 files changed

+52
-3
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Authors
7474
- Marty Alchin
7575
- Matheus Cansian (`mscansian <https://github.com/mscansian>`_)
7676
- Mauricio de Abreu Antunes
77+
- Maxim Zemskov (`MaximZemskov <https://github.com/MaximZemskov>`_)
7778
- Micah Denbraver
7879
- Michael England
7980
- Miguel Vargas

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Unreleased
55
----------
66
- Add default date to ``bulk_create_with_history`` and ``bulk_update_with_history`` (gh-687)
77
- Exclude ManyToManyFields when using ``bulk_create_with_history`` (gh-699)
8+
- Added ``--excluded_fields`` argument to ``clean_duplicate_history`` command (gh-674)
89

910
2.11.0 (2020-06-20)
1011
-------------------

docs/utils.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ so you can schedule, for instance, an hourly cronjob such as
2424
2525
$ python manage.py clean_duplicate_history -m 60 --auto
2626
27+
You can also use ``--excluded_fields`` to provide a list of fields to be excluded
28+
from the duplicate check
29+
30+
.. code-block:: bash
31+
32+
$ python manage.py clean_duplicate_history --auto --excluded_fields field1 field2
2733
2834
clean_old_history
2935
-----------------------

simple_history/management/commands/clean_duplicate_history.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,15 @@ def add_arguments(self, parser):
3131
parser.add_argument(
3232
"-m", "--minutes", type=int, help="Only search the last MINUTES of history"
3333
)
34+
parser.add_argument(
35+
"--excluded_fields",
36+
nargs="+",
37+
help="List of fields to be excluded from the diff_against check",
38+
)
3439

3540
def handle(self, *args, **options):
3641
self.verbosity = options["verbosity"]
42+
self.excluded_fields = options.get("excluded_fields")
3743

3844
to_process = set()
3945
model_strings = options.get("models", []) or args
@@ -109,7 +115,7 @@ def log(self, message, verbosity_level=1):
109115
self.stdout.write(message)
110116

111117
def _check_and_delete(self, entry1, entry2, dry_run=True):
112-
delta = entry1.diff_against(entry2)
118+
delta = entry1.diff_against(entry2, excluded_fields=self.excluded_fields)
113119
if not delta.changed_fields:
114120
if not dry_run:
115121
entry1.delete()

simple_history/models.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,19 +586,22 @@ def __get__(self, instance, owner):
586586

587587

588588
class HistoricalChanges(object):
589-
def diff_against(self, old_history):
589+
def diff_against(self, old_history, excluded_fields=None):
590590
if not isinstance(old_history, type(self)):
591591
raise TypeError(
592592
("unsupported type(s) for diffing: " "'{}' and '{}'").format(
593593
type(self), type(old_history)
594594
)
595595
)
596-
596+
if excluded_fields is None:
597+
excluded_fields = []
597598
changes = []
598599
changed_fields = []
599600
old_values = model_to_dict(old_history.instance)
600601
current_values = model_to_dict(self.instance)
601602
for field, new_value in current_values.items():
603+
if field in excluded_fields:
604+
continue
602605
if field in old_values:
603606
old_value = old_values[field]
604607
if old_value != new_value:

simple_history/tests/tests/test_commands.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,29 @@ def test_auto_cleanup_custom_history_field(self):
386386
)
387387
self.assertEqual(CustomManagerNameModel.log.all().count(), 2)
388388

389+
def test_auto_cleanup_with_excluded_fields(self):
390+
p = Poll.objects.create(
391+
question="Will this be deleted?", pub_date=datetime.now()
392+
)
393+
self.assertEqual(Poll.history.all().count(), 1)
394+
p.pub_date = p.pub_date + timedelta(days=1)
395+
p.save()
396+
self.assertEqual(Poll.history.all().count(), 2)
397+
out = StringIO()
398+
management.call_command(
399+
self.command_name,
400+
auto=True,
401+
excluded_fields=("pub_date",),
402+
stdout=out,
403+
stderr=StringIO(),
404+
)
405+
self.assertEqual(
406+
out.getvalue(),
407+
"Removed 1 historical records for "
408+
"<class 'simple_history.tests.models.Poll'>\n",
409+
)
410+
self.assertEqual(Poll.history.all().count(), 1)
411+
389412

390413
class TestCleanOldHistory(TestCase):
391414
command_name = "clean_old_history"

simple_history/tests/tests/test_models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,15 @@ def test_history_diff_with_incorrect_type(self):
659659
with self.assertRaises(TypeError):
660660
new_record.diff_against("something")
661661

662+
def test_history_diff_with_excluded_fields(self):
663+
p = Poll.objects.create(question="what's up?", pub_date=today)
664+
p.question = "what's up, man?"
665+
p.save()
666+
new_record, old_record = p.history.all()
667+
delta = new_record.diff_against(old_record, excluded_fields=("question",))
668+
self.assertEqual(delta.changed_fields, [])
669+
self.assertEqual(delta.changes, [])
670+
662671

663672
class GetPrevRecordAndNextRecordTestCase(TestCase):
664673
def assertRecordsMatch(self, record_a, record_b):

0 commit comments

Comments
 (0)