Skip to content

Commit 726c94e

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix-mongodbengine-check
2 parents 35aa569 + 1aaba50 commit 726c94e

File tree

8 files changed

+110
-4
lines changed

8 files changed

+110
-4
lines changed

AUTHORS.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Authors
3131
- Rajesh Pappula
3232
- Rod Xavier Bondoc
3333
- Ross Lote
34+
- Ross Mechanic
3435
- Steven Klass
3536
- Steeve Chailloux
3637
- Trey Hunner
@@ -40,6 +41,7 @@ Authors
4041
- Michael England
4142
- Gregory Bataille
4243
- Jesse Shapiro
44+
- Kevin Foster
4345
- Shane Engelman
4446

4547
Background

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Unreleased
55
----------
66
- Use get_queryset rather than model.objects in history_view. (gh-303)
77
- Change ugettext calls in models.py to ugettext_lazy
8+
- Resolve issue where model references itself (gh-278)
89

910
1.9.0 (2017-06-11)
1011
------------------

simple_history/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def history_form_view(self, request, object_id, version_id):
162162
'is_popup': False,
163163
'media': mark_safe(self.media + admin_form.media),
164164
'errors': helpers.AdminErrorList(form, formsets),
165-
'app_label': model._meta.app_label,
165+
'app_label': original_opts.app_label,
166166
'original_opts': original_opts,
167167
'changelist_url': reverse('%s:%s_%s_changelist' % url_triplet),
168168
'change_url': reverse('%s:%s_%s_change' % url_triplet,

simple_history/models.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,17 @@ def copy_fields(self, model):
172172
field_arguments['to_field'] = old_field.to_fields[0]
173173
if getattr(old_field, 'db_column', None):
174174
field_arguments['db_column'] = old_field.db_column
175+
176+
# If old_field.rel.to is 'self' then we have a case where object has a foreign key
177+
# to itself. In this case we update need to set the `to` value of the field
178+
# to be set to a model. We can use the old_field.model value.
179+
if isinstance(old_field.rel.to, str) and old_field.rel.to == 'self':
180+
object_to = old_field.model
181+
else:
182+
object_to = old_field.rel.to
183+
175184
field = FieldType(
176-
old_field.rel.to,
185+
object_to,
177186
related_name='+',
178187
null=True,
179188
blank=True,

simple_history/tests/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.contrib import admin
44

55
from simple_history.admin import SimpleHistoryAdmin
6-
from .models import Poll, Choice, Person, Book, Document, Paper, Employee
6+
from .models import Poll, Choice, Person, Book, Document, Paper, Employee, ConcreteExternal
77

88

99
class PersonAdmin(SimpleHistoryAdmin):
@@ -22,3 +22,4 @@ class ChoiceAdmin(SimpleHistoryAdmin):
2222
admin.site.register(Document, SimpleHistoryAdmin)
2323
admin.site.register(Paper, SimpleHistoryAdmin)
2424
admin.site.register(Employee, SimpleHistoryAdmin)
25+
admin.site.register(ConcreteExternal, SimpleHistoryAdmin)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from __future__ import unicode_literals
2+
3+
from django.db import models
4+
from simple_history.models import HistoricalRecords
5+
6+
7+
class AbstractExternal(models.Model):
8+
history = HistoricalRecords(inherit=True)
9+
10+
class Meta:
11+
abstract = True
12+
app_label = 'external'

simple_history/tests/models.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
from __future__ import unicode_literals
22

33
from django.db import models
4+
from django import VERSION
45

56
from simple_history.models import HistoricalRecords
67
from simple_history import register
78

89
from .custom_user.models import CustomUser as User
910

11+
try:
12+
from django.apps import apps
13+
except ImportError: # Django < 1.7
14+
from django.db.models import get_model
15+
else:
16+
get_model = apps.get_model
17+
18+
# 1.6 has different way of importing models
19+
if VERSION[:3] >= (1, 7, 0):
20+
from .external.models.model1 import AbstractExternal
21+
else:
22+
class AbstractExternal(models.Model):
23+
history = HistoricalRecords(inherit=True)
24+
25+
class Meta:
26+
abstract = True
27+
app_label = 'external'
28+
1029

1130
class Poll(models.Model):
1231
question = models.CharField(max_length=200)
@@ -341,6 +360,13 @@ class UntrackedConcreteBase(models.Model):
341360
pass
342361

343362

363+
class ConcreteExternal(AbstractExternal):
364+
name = models.CharField(max_length=50)
365+
366+
class Meta:
367+
app_label = 'tests'
368+
369+
344370
class TrackedWithAbstractBase(TrackedAbstractBaseA):
345371
pass
346372

simple_history/tests/tests/test_admin.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from simple_history.models import HistoricalRecords
1515
from simple_history.admin import SimpleHistoryAdmin, get_complete_version
16-
from ..models import Book, Person, Poll, State, Employee, Choice
16+
from ..models import Book, Person, Poll, State, Employee, Choice, ConcreteExternal
1717

1818
try:
1919
from django.contrib.admin.utils import quote
@@ -551,3 +551,58 @@ def test_history_form_view_getting_history_with_setting_off(self):
551551
}
552552
mock_render.assert_called_once_with(
553553
request, admin.object_history_form_template, context, **extra_kwargs)
554+
555+
def test_history_form_view_getting_history_abstract_external(self):
556+
request = RequestFactory().post('/')
557+
request.session = 'session'
558+
request._messages = FallbackStorage(request)
559+
request.user = self.user
560+
request.POST = {'_change_history': True}
561+
562+
obj = ConcreteExternal.objects.create(name='test')
563+
obj.name = "new_test"
564+
obj.save()
565+
history = obj.history.all()[0]
566+
567+
admin_site = AdminSite()
568+
admin = SimpleHistoryAdmin(ConcreteExternal, admin_site)
569+
570+
with patch('simple_history.admin.render') as mock_render:
571+
with patch('simple_history.admin.SIMPLE_HISTORY_EDIT', True):
572+
admin.history_form_view(request, obj.id, history.pk)
573+
574+
context = {
575+
# Verify this is set for history object
576+
'original': history.instance,
577+
'change_history': True,
578+
579+
'title': 'Revert %s' % force_text(history.instance),
580+
'adminform': ANY,
581+
'object_id': obj.id,
582+
'is_popup': False,
583+
'media': ANY,
584+
'errors': ANY,
585+
'app_label': 'tests',
586+
'original_opts': ANY,
587+
'changelist_url': '/admin/tests/concreteexternal/',
588+
'change_url': ANY,
589+
'history_url': '/admin/tests/concreteexternal/{pk}/history/'.format(
590+
pk=obj.pk),
591+
'add': False,
592+
'change': True,
593+
'has_add_permission': admin.has_add_permission(request),
594+
'has_change_permission': admin.has_change_permission(
595+
request, obj),
596+
'has_delete_permission': admin.has_delete_permission(
597+
request, obj),
598+
'has_file_field': True,
599+
'has_absolute_url': False,
600+
'form_url': '',
601+
'opts': ANY,
602+
'content_type_id': ANY,
603+
'save_as': admin.save_as,
604+
'save_on_top': admin.save_on_top,
605+
'root_path': getattr(admin_site, 'root_path', None),
606+
}
607+
mock_render.assert_called_once_with(
608+
request, admin.object_history_form_template, context, **extra_kwargs)

0 commit comments

Comments
 (0)