Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added possibility to specify a default user for bulk_create_with_history #636

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Authors
- Alexander Anikeev
- Amanda Ng (`AmandaCLNg <https://github.com/AmandaCLNg>`_)
- Ben Lawson (`blawson <https://github.com/blawson>`_)
- Benjamin Mampaey (`bmampaey <https://github.com/bmampaey>`_)
- `bradford281 <https://github.com/bradford281>`_
- Brian Armstrong (`barm <https://github.com/barm>`_)
- Buddy Lindsey, Jr.
Expand Down
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Unreleased
- Add setting to convert `FileField` to `CharField` instead of `TextField` (gh-623)
- import model `ContentType` in `SimpleHistoryAdmin` using `django_apps.get_model`
to avoid possible `AppRegistryNotReady` exception (gh-630)
- Add default user to `bulk_create_with_history`

2.8.0 (2019-12-02)
------------------
Expand Down
8 changes: 8 additions & 0 deletions docs/common_issues.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ can add `changeReason` on each instance:
>>> Poll.history.get(id=data[0].id).history_change_reason
'reason'

You can also specify a default user responsible for the change ( _history_user keeps precedence)

.. code-block:: pycon

>>> user = User.objects.create_user("tester", "tester@example.com")
>>> objs = bulk_create_with_history(data, Poll, batch_size=500, default_user=user)
>>> Poll.history.get(id=data[0].id).history_user == user
True

QuerySet Updates with History
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions simple_history/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ def _as_of_set(self, date):
continue
yield last_change.instance

def bulk_history_create(self, objs, batch_size=None):
def bulk_history_create(self, objs, batch_size=None, default_user=None):
"""Bulk create the history for the objects specified by objs"""

historical_instances = []
for instance in objs:
row = self.model(
history_date=getattr(instance, "_history_date", now()),
history_user=getattr(instance, "_history_user", None),
history_user=getattr(instance, "_history_user", default_user),
history_change_reason=getattr(instance, "changeReason", ""),
history_type="+",
**{
Expand Down
9 changes: 9 additions & 0 deletions simple_history/tests/tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,15 @@ def test_bulk_history_create_with_change_reason(self):
)
)

def test_bulk_history_create_with_default_user(self):
user = User.objects.create_user("tester", "tester@example.com")

Poll.history.bulk_history_create(self.data, default_user=user)

self.assertTrue(
all([history.history_user == user for history in Poll.history.all()])
)

def test_bulk_history_create_on_objs_without_ids(self):
self.data = [
Poll(question="Question 1", pub_date=datetime.now()),
Expand Down
12 changes: 12 additions & 0 deletions simple_history/tests/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.auth import get_user_model
from django.db import IntegrityError
from django.test import TestCase, TransactionTestCase
from django.utils.timezone import now
Expand All @@ -13,6 +14,8 @@
)
from simple_history.utils import bulk_create_with_history

User = get_user_model()


class BulkCreateWithHistoryTestCase(TestCase):
def setUp(self):
Expand All @@ -37,6 +40,15 @@ def test_bulk_create_history(self):
self.assertEqual(Poll.objects.count(), 5)
self.assertEqual(Poll.history.count(), 5)

def test_bulk_create_history_with_default_user(self):
user = User.objects.create_user("tester", "tester@example.com")

bulk_create_with_history(self.data, Poll, default_user=user)

self.assertTrue(
all([history.history_user == user for history in Poll.history.all()])
)

def test_bulk_create_history_num_queries_is_two(self):
with self.assertNumQueries(2):
bulk_create_with_history(self.data, Poll)
Expand Down
10 changes: 7 additions & 3 deletions simple_history/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def get_history_model_for_model(model):
return get_history_manager_for_model(model).model


def bulk_create_with_history(objs, model, batch_size=None):
def bulk_create_with_history(objs, model, batch_size=None, default_user=None):
"""
Bulk create the objects specified by objs while also bulk creating
their history (all in one transaction).
Expand All @@ -56,7 +56,9 @@ def bulk_create_with_history(objs, model, batch_size=None):
objs_with_id = model.objects.bulk_create(objs, batch_size=batch_size)
if objs_with_id and objs_with_id[0].pk:
second_transaction_required = False
history_manager.bulk_history_create(objs_with_id, batch_size=batch_size)
history_manager.bulk_history_create(
objs_with_id, batch_size=batch_size, default_user=default_user
)
if second_transaction_required:
obj_list = []
with transaction.atomic(savepoint=False):
Expand All @@ -65,6 +67,8 @@ def bulk_create_with_history(objs, model, batch_size=None):
filter(lambda x: x[1] is not None, model_to_dict(obj).items())
)
obj_list += model.objects.filter(**attributes)
history_manager.bulk_history_create(obj_list, batch_size=batch_size)
history_manager.bulk_history_create(
obj_list, batch_size=batch_size, default_user=default_user
)
objs_with_id = obj_list
return objs_with_id