Skip to content

Commit bad5d95

Browse files
committed
Factor auto field logic to its own method, detect engine using writable route
1 parent 687637a commit bad5d95

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

simple_history/models.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from django.apps import apps # Django >= 1.7
77
except ImportError:
88
apps = None
9-
from django.db import models
9+
from django.db import models, router
1010
from django.db.models.fields.related import RelatedField
1111
from django.db.models.related import RelatedObject
1212
from django.conf import settings
@@ -53,8 +53,6 @@ def python_2_unicode_compatible(klass):
5353

5454
registered_models = {}
5555

56-
nonrel_dbs = ('django_mongodb_engine')
57-
5856

5957
class HistoricalRecords(object):
6058
thread = threading.local()
@@ -267,11 +265,7 @@ def get_field(self, other, cls):
267265
if isinstance(to_field, models.OneToOneField):
268266
field = self.get_one_to_one_field(to_field, other)
269267
elif isinstance(to_field, models.AutoField):
270-
# Check if AutoField is string for django-non-rel support
271-
if settings.DATABASES['default']['ENGINE'] in nonrel_dbs:
272-
field.__class__ = models.TextField
273-
else:
274-
field.__class__ = models.IntegerField
268+
field.__class__ = convert_auto_field(to_field)
275269
else:
276270
field.__class__ = to_field.__class__
277271
excluded_prefixes = ("_", "__")
@@ -323,13 +317,7 @@ def transform_field(field):
323317
"""Customize field appropriately for use in historical model"""
324318
field.name = field.attname
325319
if isinstance(field, models.AutoField):
326-
# The historical model gets its own AutoField, so any
327-
# existing one must be replaced with an IntegerField.
328-
if settings.DATABASES['default']['ENGINE'] in nonrel_dbs:
329-
# Check if AutoField is string for django-non-rel support
330-
field.__class__ = models.TextField
331-
else:
332-
field.__class__ = models.IntegerField
320+
field.__class__ = convert_auto_field(field)
333321

334322
elif isinstance(field, models.FileField):
335323
# Don't copy file, just path.
@@ -348,6 +336,19 @@ def transform_field(field):
348336
field.serialize = True
349337

350338

339+
def convert_auto_field(field):
340+
"""Convert AutoField to a non-incrementing type
341+
342+
The historical model gets its own AutoField, so any existing one
343+
must be replaced with an IntegerField.
344+
"""
345+
connection = router.db_for_write(field.model)
346+
if settings.DATABASES[connection]['ENGINE'] in ('django_mongodb_engine',):
347+
# Check if AutoField is string for django-non-rel support
348+
return models.TextField
349+
return models.IntegerField
350+
351+
351352
class HistoricalObjectDescriptor(object):
352353
def __init__(self, model):
353354
self.model = model

simple_history/tests/tests/test_models.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
User = get_user_model()
88
except ImportError: # django 1.4 compatibility
99
from django.contrib.auth.models import User
10+
from django.db import models
1011
from django.db.models.loading import get_model
1112
from django.test import TestCase
1213
from django.core.files.base import ContentFile
1314

14-
from simple_history.models import HistoricalRecords
15+
from simple_history.models import HistoricalRecords, convert_auto_field
1516
from simple_history import register
1617
from ..models import (
1718
AdminProfile, Bookcase, MultiOneToOne, Poll, Choice, Restaurant, Person,
@@ -469,3 +470,32 @@ def test_import_related(self):
469470
def test_string_related(self):
470471
field_object = HistoricalState._meta.get_field_by_name('library_id')[0]
471472
self.assertEqual(field_object.related.model, State)
473+
474+
475+
class TestConvertAutoField(TestCase):
476+
"""Check what AutoFields get converted to."""
477+
478+
def setUp(self):
479+
for field in Poll._meta.fields:
480+
if isinstance(field, models.AutoField):
481+
self.field = field
482+
break
483+
484+
def test_relational(self):
485+
"""Relational test
486+
487+
Default Django ORM uses an integer-based auto field.
488+
"""
489+
with self.settings(DATABASES={'default': {
490+
'ENGINE': 'django.db.backends.postgresql_psycopg2'}}):
491+
assert convert_auto_field(self.field) == models.IntegerField
492+
493+
def test_non_relational(self):
494+
"""Non-relational test
495+
496+
MongoDB uses a string-based auto field. We need to make sure
497+
the converted field type is string.
498+
"""
499+
with self.settings(DATABASES={'default': {
500+
'ENGINE': 'django_mongodb_engine'}}):
501+
assert convert_auto_field(self.field) == models.TextField

0 commit comments

Comments
 (0)