From e87758f42bd17ac19685b322db4a9349e8d9c613 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Mon, 1 May 2023 17:32:29 +0500 Subject: [PATCH] add AsymmetricRelatedField --- rest_framework_extensions/fields.py | 15 +++++- tests_app/tests/unit/fields/__init__.py | 0 tests_app/tests/unit/fields/models.py | 10 ++++ tests_app/tests/unit/fields/serializers.py | 21 ++++++++ tests_app/tests/unit/fields/tests.py | 53 +++++++++++++++++++ .../tests/unit/migrations/0001_initial.py | 19 +++++++ 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests_app/tests/unit/fields/__init__.py create mode 100644 tests_app/tests/unit/fields/models.py create mode 100644 tests_app/tests/unit/fields/serializers.py create mode 100644 tests_app/tests/unit/fields/tests.py diff --git a/rest_framework_extensions/fields.py b/rest_framework_extensions/fields.py index dd9f069..625ab7f 100644 --- a/rest_framework_extensions/fields.py +++ b/rest_framework_extensions/fields.py @@ -1,4 +1,6 @@ -from rest_framework.relations import HyperlinkedRelatedField +from rest_framework.relations import HyperlinkedRelatedField, PrimaryKeyRelatedField + +from rest_framework import serializers class ResourceUriField(HyperlinkedRelatedField): @@ -26,3 +28,14 @@ class Meta: def __init__(self, *args, **kwargs): kwargs.setdefault('source', '*') super().__init__(*args, **kwargs) + + +class AsymmetricRelatedField(serializers.PrimaryKeyRelatedField): + def __init__( + self, serializer_class, *args, **kwargs + ) -> None: + self.serializer_class = serializer_class + super().__init__(*args, **kwargs) + + def to_representation(self, value): + return self.serializer_class(value).data \ No newline at end of file diff --git a/tests_app/tests/unit/fields/__init__.py b/tests_app/tests/unit/fields/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests_app/tests/unit/fields/models.py b/tests_app/tests/unit/fields/models.py new file mode 100644 index 0000000..35ae251 --- /dev/null +++ b/tests_app/tests/unit/fields/models.py @@ -0,0 +1,10 @@ +from django.db import models + + +class RelatedModel(models.Model): + name = models.CharField(max_length=100) + + +class SomeModel(models.Model): + name = models.CharField(max_length=100) + related_model = models.ForeignKey(RelatedModel, on_delete=models.CASCADE) diff --git a/tests_app/tests/unit/fields/serializers.py b/tests_app/tests/unit/fields/serializers.py new file mode 100644 index 0000000..91a6edd --- /dev/null +++ b/tests_app/tests/unit/fields/serializers.py @@ -0,0 +1,21 @@ +from rest_framework import serializers +from rest_framework_extensions.fields import AsymmetricRelatedField + +from .models import SomeModel, RelatedModel + + +class RelatedModelSerializer(serializers.ModelSerializer): + class Meta: + model = RelatedModel + fields = ('id', 'name') + + +class SomeModelSerializer(serializers.ModelSerializer): + related_model = AsymmetricRelatedField( + serializer_class=RelatedModelSerializer, + queryset=RelatedModel.objects.all() + ) + + class Meta: + model = SomeModel + fields = ('id', 'name', 'related_model') \ No newline at end of file diff --git a/tests_app/tests/unit/fields/tests.py b/tests_app/tests/unit/fields/tests.py new file mode 100644 index 0000000..b149d5c --- /dev/null +++ b/tests_app/tests/unit/fields/tests.py @@ -0,0 +1,53 @@ +from django.test import TestCase +from rest_framework import serializers +from .models import SomeModel, RelatedModel +from .serializers import SomeModelSerializer, RelatedModelSerializer +from rest_framework_extensions.fields import AsymmetricRelatedField + + +class TestAsymmetricRelatedField(TestCase): + def setUp(self): + self.related_model1 = RelatedModel.objects.create(name='related_model1') + self.related_model2 = RelatedModel.objects.create(name='related_model2') + self.some_model = SomeModel.objects.create( + name='some_model', related_model=self.related_model1) + + def test_to_representation(self): + field = AsymmetricRelatedField(serializer_class=RelatedModelSerializer) + result = field.to_representation(self.related_model1) + self.assertEqual( + result, {'id': self.related_model1.id, 'name': 'related_model1'}) + + def test_create(self): + data = { + 'name': 'new_some_model', + 'related_model': self.related_model2.id + } + serializer = SomeModelSerializer(data=data) + self.assertTrue(serializer.is_valid()) + instance = serializer.save() + self.assertEqual(instance.name, 'new_some_model') + self.assertEqual(instance.related_model, self.related_model2) + + def test_update(self): + data = { + 'name': 'updated_some_model', + 'related_model': self.related_model2.id + } + serializer = SomeModelSerializer( + instance=self.some_model, data=data, partial=True) + self.assertTrue(serializer.is_valid()) + instance = serializer.save() + self.assertEqual(instance.name, 'updated_some_model') + self.assertEqual(instance.related_model, self.related_model2) + + def test_read(self): + serializer = SomeModelSerializer(instance=self.some_model) + self.assertEqual(serializer.data, { + 'id': self.some_model.id, + 'name': 'some_model', + 'related_model': { + 'id': self.related_model1.id, + 'name': 'related_model1' + } + }) diff --git a/tests_app/tests/unit/migrations/0001_initial.py b/tests_app/tests/unit/migrations/0001_initial.py index 2e5e095..c8c3db1 100644 --- a/tests_app/tests/unit/migrations/0001_initial.py +++ b/tests_app/tests/unit/migrations/0001_initial.py @@ -65,4 +65,23 @@ class Migration(migrations.Migration): ('users_liked', models.ManyToManyField(blank=True, to='unit.UserModel')), ], ), + migrations.CreateModel( + name='RelatedModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, + serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='SomeModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, + serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('related_model', + models.ForeignKey(blank=True, to='unit.RelatedModel', + on_delete=models.CASCADE)), + ], + ), ]