Skip to content

Commit

Permalink
Merge pull request #842 from matwey/feature/natural_key
Browse files Browse the repository at this point in the history
Add initial implementation for use_natural_foreign_keys support
  • Loading branch information
etianen authored Aug 24, 2020
2 parents 13a95af + 79316d4 commit 22c53e9
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 2 deletions.
4 changes: 3 additions & 1 deletion reversion/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,12 @@ def _model(self):

@cached_property
def _object_version(self):
version_options = _get_options(self._model)
data = self.serialized_data
data = force_str(data.encode("utf8"))
try:
return list(serializers.deserialize(self.format, data, ignorenonexistent=True))[0]
return list(serializers.deserialize(self.format, data, ignorenonexistent=True,
use_natural_foreign_keys=version_options.use_natural_foreign_keys))[0]
except DeserializationError:
raise RevertError(ugettext("Could not load %(object_repr)s version - incompatible version data.") % {
"object_repr": self.object_repr,
Expand Down
5 changes: 4 additions & 1 deletion reversion/revisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"format",
"for_concrete_model",
"ignore_duplicates",
"use_natural_foreign_keys",
))


Expand Down Expand Up @@ -190,6 +191,7 @@ def _add_to_revision(obj, using, model_db, explicit):
version_options.format,
(obj,),
fields=version_options.fields,
use_natural_foreign_keys=version_options.use_natural_foreign_keys,
),
object_repr=force_str(obj),
)
Expand Down Expand Up @@ -364,7 +366,7 @@ def _get_senders_and_signals(model):


def register(model=None, fields=None, exclude=(), follow=(), format="json",
for_concrete_model=True, ignore_duplicates=False):
for_concrete_model=True, ignore_duplicates=False, use_natural_foreign_keys=False):
def register(model):
# Prevent multiple registration.
if is_registered(model):
Expand All @@ -388,6 +390,7 @@ def register(model):
format=format,
for_concrete_model=for_concrete_model,
ignore_duplicates=ignore_duplicates,
use_natural_foreign_keys=use_natural_foreign_keys,
)
# Register the model.
_registered_models[_get_registration_key(model)] = version_options
Expand Down
33 changes: 33 additions & 0 deletions tests/test_app/migrations/0002_naturalkey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 2.2.12 on 2020-08-15 11:42

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('test_app', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='TestModelWithNaturalKey',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(default='v1', max_length=191)),
],
),
migrations.AlterField(
model_name='testmodelnestedinline',
name='nested_inline_name',
field=models.CharField(default='v1', max_length=191),
),
migrations.CreateModel(
name='TestModelInlineByNaturalKey',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('test_model', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='test_app.TestModelWithNaturalKey')),
],
),
]
24 changes: 24 additions & 0 deletions tests/test_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,27 @@ class TestMeta(models.Model):
name = models.CharField(
max_length=191,
)


class TestModelWithNaturalKeyManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)


class TestModelWithNaturalKey(models.Model):
name = models.CharField(
max_length=191,
default="v1",
)

objects = TestModelWithNaturalKeyManager()

def natural_key(self):
return (self.name,)


class TestModelInlineByNaturalKey(models.Model):
test_model = models.ForeignKey(
TestModelWithNaturalKey,
on_delete=models.CASCADE,
)
23 changes: 23 additions & 0 deletions tests/test_app/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from test_app.models import (
TestModel, TestModelRelated, TestModelParent, TestModelInline,
TestModelNestedInline,
TestModelInlineByNaturalKey, TestModelWithNaturalKey,
)
from test_app.tests.base import TestBase, TestModelMixin, TestModelParentMixin
import json


class GetForModelTest(TestModelMixin, TestBase):
Expand Down Expand Up @@ -412,3 +414,24 @@ def testRevertDeleteNestedInline(self):
self.assertEqual(
list(child_a.testmodelnestedinline_set.all()), [grandchild_a]
)


class NaturalKeyTest(TestBase):

def setUp(self):
reversion.register(TestModelInlineByNaturalKey, use_natural_foreign_keys=True)
reversion.register(TestModelWithNaturalKey)

def testNaturalKeyInline(self):
with reversion.create_revision():
inline = TestModelWithNaturalKey.objects.create()
obj = TestModelInlineByNaturalKey.objects.create(test_model=inline)
self.assertEqual(json.loads(Version.objects.get_for_object(obj).get().serialized_data), [{
'fields': {'test_model': ['v1']},
'model': 'test_app.testmodelinlinebynaturalkey',
'pk': 1
}])
self.assertEqual(Version.objects.get_for_object(obj).get().field_dict, {
'test_model_id': 1,
'id': 1,
})

0 comments on commit 22c53e9

Please sign in to comment.