Skip to content

Commit b5a650a

Browse files
authored
Merge pull request #274 from joaojunior/ExcludeAndIncludeFields
Exclude fields
2 parents c07d907 + 1f9d529 commit b5a650a

File tree

5 files changed

+64
-9
lines changed

5 files changed

+64
-9
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Authors
1515
- Grzegorz Bialy
1616
- Hamish Downer
1717
- James Pulec
18+
- Joao Junior(@joaojunior)
1819
- Joao Pedro Francese
1920
- jofusa
2021
- John Whitlock

docs/advanced.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,32 @@ You can use the ``table_name`` parameter with both ``HistoricalRecords()`` or
214214
215215
register(Question, table_name='polls_question_history')
216216
217+
Choosing fields to not be stored
218+
--------------------------------
219+
220+
It is possible to use the parameter ``excluded_fields`` to choose which fields
221+
will be stored on every create/update/delete.
222+
223+
For example, if you have the model:
224+
225+
.. code-block:: python
226+
227+
class PollWithExcludeFields(models.Model):
228+
question = models.CharField(max_length=200)
229+
pub_date = models.DateTimeField('date published')
230+
231+
And you don't want to store the changes for the field ``pub_date``, it is necessary to update the model to:
232+
233+
.. code-block:: python
234+
235+
class PollWithExcludeFields(models.Model):
236+
question = models.CharField(max_length=200)
237+
pub_date = models.DateTimeField('date published')
238+
239+
history = HistoricalRecords(excluded_fields=['pub_date'])
240+
241+
By default, django-simple-history stores the changes for all fields in the model.
242+
217243
Change Reason
218244
-------------
219245

simple_history/models.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,15 @@ class HistoricalRecords(object):
3636
thread = threading.local()
3737

3838
def __init__(self, verbose_name=None, bases=(models.Model,),
39-
user_related_name='+', table_name=None, inherit=False):
39+
user_related_name='+', table_name=None, inherit=False,
40+
excluded_fields=None):
4041
self.user_set_verbose_name = verbose_name
4142
self.user_related_name = user_related_name
4243
self.table_name = table_name
4344
self.inherit = inherit
45+
if excluded_fields is None:
46+
excluded_fields = []
47+
self.excluded_fields = excluded_fields
4448
try:
4549
if isinstance(bases, six.string_types):
4650
raise TypeError
@@ -134,13 +138,20 @@ def create_history_model(self, model):
134138
return python_2_unicode_compatible(
135139
type(str(name), self.bases, attrs))
136140

141+
def fields_included(self, model):
142+
fields = []
143+
for field in model._meta.fields:
144+
if field.name not in self.excluded_fields:
145+
fields.append(field)
146+
return fields
147+
137148
def copy_fields(self, model):
138149
"""
139150
Creates copies of the model's original fields, returning
140151
a dictionary mapping field name to copied field object.
141152
"""
142153
fields = {}
143-
for field in model._meta.fields:
154+
for field in self.fields_included(model):
144155
field = copy.copy(field)
145156
try:
146157
field.remote_field = copy.copy(field.remote_field)
@@ -212,7 +223,7 @@ def get_instance(self):
212223
('~', _('Changed')),
213224
('-', _('Deleted')),
214225
)),
215-
'history_object': HistoricalObjectDescriptor(model),
226+
'history_object': HistoricalObjectDescriptor(model, self.fields_included(model)),
216227
'instance': property(get_instance),
217228
'instance_type': model,
218229
'revert_url': revert_url,
@@ -252,7 +263,7 @@ def create_historical_record(self, instance, history_type):
252263
history_change_reason = getattr(instance, 'changeReason', None)
253264
manager = getattr(instance, self.manager_name)
254265
attrs = {}
255-
for field in instance._meta.fields:
266+
for field in self.fields_included(instance):
256267
attrs[field.attname] = getattr(instance, field.attname)
257268
manager.create(history_date=history_date, history_type=history_type,
258269
history_user=history_user,
@@ -308,10 +319,11 @@ def convert_auto_field(field):
308319

309320

310321
class HistoricalObjectDescriptor(object):
311-
def __init__(self, model):
322+
def __init__(self, model, fields_included):
312323
self.model = model
324+
self.fields_included = fields_included
313325

314326
def __get__(self, instance, owner):
315327
values = (getattr(instance, f.attname)
316-
for f in self.model._meta.fields)
328+
for f in self.fields_included)
317329
return self.model(*values)

simple_history/tests/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ class Poll(models.Model):
1515
history = HistoricalRecords()
1616

1717

18+
class PollWithExcludeFields(models.Model):
19+
question = models.CharField(max_length=200)
20+
pub_date = models.DateTimeField('date published')
21+
22+
history = HistoricalRecords(excluded_fields=['pub_date'])
23+
24+
1825
class Temperature(models.Model):
1926
location = models.CharField(max_length=200)
2027
temperature = models.IntegerField()

simple_history/tests/tests/test_models.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
Country, Document, Employee, ExternalModel1,
2020
ExternalModel3, FileModel, HistoricalChoice,
2121
HistoricalCustomFKError, HistoricalPoll, HistoricalState,
22-
Library, MultiOneToOne, Person, Poll, PollInfo, Province,
23-
Restaurant, SelfFK, Series, SeriesWork, State,
24-
Temperature, UnicodeVerboseName, WaterLevel)
22+
Library, MultiOneToOne, Person, Poll, PollInfo,
23+
PollWithExcludeFields, Province, Restaurant, SelfFK,
24+
Series, SeriesWork, State, Temperature,
25+
UnicodeVerboseName, WaterLevel)
2526

2627
try:
2728
from django.apps import apps
@@ -334,6 +335,14 @@ def test_foreignkey_primarykey(self):
334335
poll_info = PollInfo(poll=poll)
335336
poll_info.save()
336337

338+
def test_model_with_excluded_fields(self):
339+
p = PollWithExcludeFields(question="what's up?", pub_date=today)
340+
p.save()
341+
history = PollWithExcludeFields.history.all()[0]
342+
all_fields_names = [f.name for f in history._meta.fields]
343+
self.assertIn('question', all_fields_names)
344+
self.assertNotIn('pub_date', all_fields_names)
345+
337346

338347
class CreateHistoryModelTests(unittest.TestCase):
339348

0 commit comments

Comments
 (0)