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

GH-512: allow foreign key to reference self using self str #513

Merged
merged 5 commits into from
Jan 14, 2019
Merged
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 CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Unreleased
- Add support for `using` chained manager method and save/delete keyword argument (gh-507)
- Added management command `clean_duplicate_history` to remove duplicate history entries (gh-483)
- Updated most_recent to work with excluded_fields (gh-477)
- Fixed bug that prevented self-referential foreign key from using `'self'` (gh-513)

2.6.0 (2018-12-12)
------------------
Expand Down
7 changes: 7 additions & 0 deletions simple_history/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ def copy_fields(self, model):
else:
FieldType = type(old_field)

# If field_args['to'] is 'self' then we have a case where the object
# has a foreign key to itself. If we pass the historical record's
# field to = 'self', the foreign key will point to an historical
# record rather than the base record. We can use old_field.model here.
if field_args.get("to", None) == "self":
field_args["to"] = old_field.model

# Override certain arguments passed when creating the field
# so that they work for the historical field.
field_args.update(
Expand Down
10 changes: 10 additions & 0 deletions simple_history/tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,3 +553,13 @@ class CustomNameModel(models.Model):
class CustomManagerNameModel(models.Model):
name = models.CharField(max_length=15)
log = HistoricalRecords()


class ForeignKeyToSelfModel(models.Model):
fk_to_self = models.ForeignKey(
"ForeignKeyToSelfModel", null=True, related_name="+", on_delete=models.CASCADE
)
fk_to_self_using_str = models.ForeignKey(
"self", null=True, related_name="+", on_delete=models.CASCADE
)
history = HistoricalRecords()
21 changes: 18 additions & 3 deletions simple_history/tests/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import unicode_literals

import unittest

import uuid
import warnings
from datetime import datetime, timedelta
Expand Down Expand Up @@ -43,6 +44,7 @@
ExternalModel1,
ExternalModel3,
FileModel,
ForeignKeyToSelfModel,
HistoricalChoice,
HistoricalCustomFKError,
HistoricalPoll,
Expand Down Expand Up @@ -583,7 +585,6 @@ def setUp(self):
self.poll.save()

def test_get_prev_record(self):

self.poll.question = "ask questions?"
self.poll.save()
self.poll.question = "eh?"
Expand Down Expand Up @@ -1203,7 +1204,6 @@ def test_signal_is_able_to_retrieve_request_from_thread(self):

class WarningOnAbstractModelWithInheritFalseTest(TestCase):
def test_warning_on_abstract_model_with_inherit_false(self):

with warnings.catch_warnings(record=True) as w:

class AbstractModelWithInheritFalse(models.Model):
Expand All @@ -1224,7 +1224,6 @@ class Meta:


class MultiDBWithUsingTest(TestCase):

"""Asserts historical manager respects `using()` and the `using`
keyword argument in `save()`.
"""
Expand Down Expand Up @@ -1309,3 +1308,19 @@ def test_multidb_with_using_keyword_in_save_and_delete(self):
.order_by("history_date")
],
)


class ForeignKeyToSelfTest(TestCase):
def setUp(self):
self.model = ForeignKeyToSelfModel
self.history_model = self.model.history.model

def test_foreign_key_to_self_using_model_str(self):
self.assertEqual(
self.model, self.history_model.fk_to_self.field.remote_field.model
)

def test_foreign_key_to_self_using_self_str(self):
self.assertEqual(
self.model, self.history_model.fk_to_self_using_str.field.remote_field.model
)