def test_create_event(): """ Verifies events can be created manually and are linked with proper context """ m = ddf.G('tests.EventModel') with pytest.raises(ValueError, match='not a registered event'): pghistory.create_event(m, label='invalid_event') event = pghistory.create_event(m, label='manual_event') assert event.pgh_label == 'manual_event' assert event.dt_field == m.dt_field assert event.int_field == m.int_field assert event.pgh_context is None event = pghistory.create_event(m, label='no_pgh_obj_manual_event') assert event.pgh_label == 'no_pgh_obj_manual_event' assert event.dt_field == m.dt_field assert event.int_field == m.int_field assert event.pgh_context is None # Context should be added properly with pghistory.context(hello='world') as ctx: event = pghistory.create_event(m, label='manual_event') assert event.pgh_label == 'manual_event' assert event.dt_field == m.dt_field assert event.int_field == m.int_field assert event.pgh_context.id == ctx.id assert event.pgh_context.metadata == {'hello': 'world'}
def middleware(request): if request.method in ('POST', 'PUT', 'PATCH'): with pghistory.context( user=request.user.id if hasattr(request, 'user') else None, url=request.path, ): if isinstance(request, DjangoWSGIRequest): # pragma: no branch request.__class__ = WSGIRequest return get_response(request) else: return get_response(request)
def test_custom_snapshot_model_tracking(mocker): """ Tests the snapshot trigger when a custom snapshot model is declared """ # There is no context foreign key, so no context should be saved with pghistory.context(): tracking = ddf.G(test_models.SnapshotModel, int_field=0) assert tracking.custom_related_name.exists() tracking.int_field = 1 tracking.save() # Do an empty update to make sure extra snapshot aren't tracked tracking.save() assert list(tracking.custom_related_name.order_by('pgh_id').values()) == [ { 'pgh_id': mocker.ANY, 'id': tracking.id, 'pgh_label': 'custom_snapshot', 'int_field': 0, 'fk_field_id': tracking.fk_field_id, 'fk_field2_id': None, 'pgh_obj_id': tracking.id, 'pgh_created_at': mocker.ANY, }, { 'pgh_id': mocker.ANY, 'id': tracking.id, 'pgh_label': 'custom_snapshot', 'int_field': 1, 'fk_field_id': tracking.fk_field_id, 'fk_field2_id': None, 'pgh_obj_id': tracking.id, 'pgh_created_at': mocker.ANY, }, ] assert list( tracking.custom_related_name.order_by('pgh_id').values() ) == list( test_models.CustomSnapshotModel.objects.order_by('pgh_id').values() ) # Deleting the model will not delete the tracking model since it # has a custom foreign key tracking.delete() assert test_models.CustomSnapshotModel.objects.count() == 2
def test_model_snapshot_tracking(mocker): """ Tests the snapshot trigger for any model snapshot """ # Even though the context is only set for this section of code, # it actually persists through the whole transaction (if there is # one). Since tests are ran in a transaction by default, all # subsequent events will be grouped under the same context with pghistory.context() as ctx: tracking = ddf.G( test_models.SnapshotModel, dt_field=dt.datetime(2020, 1, 1, tzinfo=dt.timezone.utc), int_field=0, fk_field=ddf.F(), ) assert tracking.snapshot.exists() tracking.dt_field = dt.datetime(2019, 1, 1, tzinfo=dt.timezone.utc) tracking.save() # Do an empty update to make sure extra snapshot aren't tracked tracking.save() # Update the int field tracking.int_field = 1 tracking.save() assert list(tracking.snapshot.order_by('pgh_id').values()) == [ { 'pgh_id': mocker.ANY, 'id': tracking.id, 'fk_field_id': tracking.fk_field_id, 'dt_field': dt.datetime(2020, 1, 1, tzinfo=dt.timezone.utc), 'pgh_label': 'snapshot', 'int_field': 0, 'pgh_obj_id': tracking.id, 'pgh_created_at': mocker.ANY, 'pgh_context_id': ctx.id, }, { 'pgh_id': mocker.ANY, 'id': tracking.id, 'dt_field': dt.datetime(2019, 1, 1, tzinfo=dt.timezone.utc), 'fk_field_id': tracking.fk_field_id, 'pgh_label': 'snapshot', 'int_field': 0, 'pgh_obj_id': tracking.id, 'pgh_created_at': mocker.ANY, 'pgh_context_id': ctx.id, }, { 'pgh_id': mocker.ANY, 'id': tracking.id, 'dt_field': dt.datetime(2019, 1, 1, tzinfo=dt.timezone.utc), 'fk_field_id': tracking.fk_field_id, 'pgh_label': 'snapshot', 'int_field': 1, 'pgh_obj_id': tracking.id, 'pgh_created_at': mocker.ANY, 'pgh_context_id': ctx.id, }, ] # Deleting the model will not delete history by default tracking.delete() assert ( apps.get_model('tests', 'SnapshotModelSnapshot').objects.count() == 3 )
def __setattr__(self, attr, value): if attr == 'user': pghistory.context(user=value.id if value else None) return super().__setattr__(attr, value)