Skip to content

Commit ebdc1ef

Browse files
committed
add reverse One to One test cases
1 parent 33e66b4 commit ebdc1ef

File tree

4 files changed

+182
-25
lines changed

4 files changed

+182
-25
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Generated by Django 4.2.16 on 2024-10-28 12:53
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("tests", "0001_initial"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="product",
15+
name="category",
16+
field=models.ForeignKey(
17+
on_delete=django.db.models.deletion.CASCADE, related_name="products", to="tests.category"
18+
),
19+
),
20+
migrations.AlterField(
21+
model_name="product",
22+
name="partners",
23+
field=models.ManyToManyField(blank=True, related_name="products", to="tests.partner"),
24+
),
25+
migrations.CreateModel(
26+
name="SupplierMetadata",
27+
fields=[
28+
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
29+
("properties", models.CharField(max_length=255)),
30+
(
31+
"supplier",
32+
models.OneToOneField(
33+
on_delete=django.db.models.deletion.CASCADE, related_name="metadata", to="tests.supplier"
34+
),
35+
),
36+
],
37+
),
38+
migrations.CreateModel(
39+
name="ProductMetadata",
40+
fields=[
41+
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
42+
("properties", models.CharField(max_length=255)),
43+
(
44+
"product",
45+
models.OneToOneField(
46+
on_delete=django.db.models.deletion.CASCADE, related_name="metadata", to="tests.product"
47+
),
48+
),
49+
],
50+
),
51+
]

tests/models.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ class Supplier(models.Model):
99
name = models.CharField(max_length=255)
1010

1111

12+
class SupplierMetadata(models.Model):
13+
supplier = models.OneToOneField(Supplier, related_name="metadata", on_delete=models.CASCADE)
14+
properties = models.CharField(max_length=255)
15+
16+
1217
class Partner(models.Model):
1318
name = models.CharField(max_length=255)
1419

@@ -21,3 +26,8 @@ class Product(models.Model):
2126
Supplier, related_name="backup_products", on_delete=models.CASCADE, null=True, blank=True
2227
)
2328
partners = models.ManyToManyField(Partner, related_name="products", blank=True)
29+
30+
31+
class ProductMetadata(models.Model):
32+
product = models.OneToOneField(Product, related_name="metadata", on_delete=models.CASCADE)
33+
properties = models.CharField(max_length=255)

tests/serializers.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
from rest_framework import serializers
22

33
from drf_sideloading.serializers import SideLoadableSerializer
4-
from tests.models import Supplier, Category, Product, Partner
4+
from tests.models import Supplier, Category, Product, Partner, ProductMetadata, SupplierMetadata
5+
6+
7+
class SupplierMetadataSerializer(serializers.ModelSerializer):
8+
class Meta:
9+
model = SupplierMetadata
10+
fields = ["supplier", "properties"]
511

612

713
class SupplierSerializer(serializers.ModelSerializer):
14+
metadata = SupplierMetadataSerializer(read_only=True)
15+
816
class Meta:
917
model = Supplier
10-
fields = ["name"]
18+
fields = ["name", "metadata"]
1119

1220

1321
class PartnerSerializer(serializers.ModelSerializer):
@@ -22,10 +30,18 @@ class Meta:
2230
fields = ["name"]
2331

2432

33+
class ProductMetadataSerializer(serializers.ModelSerializer):
34+
class Meta:
35+
model = ProductMetadata
36+
fields = ["product", "properties"]
37+
38+
2539
class ProductSerializer(serializers.ModelSerializer):
40+
metadata = ProductMetadataSerializer(read_only=True)
41+
2642
class Meta:
2743
model = Product
28-
fields = ["name", "category", "supplier", "partners"]
44+
fields = ["name", "category", "supplier", "partners", "metadata"]
2945

3046

3147
class CategorySideloadableSerializer(SideLoadableSerializer):
@@ -50,20 +66,22 @@ class ProductSideloadableSerializer(SideLoadableSerializer):
5066
backup_suppliers = SupplierSerializer(source="backup_supplier", many=True)
5167
partners = PartnerSerializer(source="partner", many=True)
5268
combined_suppliers = SupplierSerializer(many=True)
69+
metadata = ProductMetadataSerializer(many=True, read_only=True)
5370

5471
class Meta:
5572
primary = "products"
5673
prefetches = {
5774
"categories": "category",
58-
"main_suppliers": "supplier",
59-
"backup_suppliers": "backup_supplier",
75+
"main_suppliers": ["supplier", "supplier__metadata"],
76+
"backup_suppliers": ["backup_supplier", "backup_supplier__metadata"],
6077
"partners": "partners",
6178
# These can be defined to always load them, else they will be
6279
# copied over form all sources or selected sources only.
6380
"combined_suppliers": {
64-
"suppliers": ["supplier"],
65-
"backup_supplier": ["backup_supplier"],
81+
"suppliers": ["supplier", "supplier__metadata"],
82+
"backup_supplier": ["backup_supplier", "backup_supplier__metadata"],
6683
},
84+
"metadata": "metadata",
6785
}
6886

6987

@@ -74,18 +92,20 @@ class NewProductSideloadableSerializer(SideLoadableSerializer):
7492
new_backup_suppliers = SupplierSerializer(source="backup_supplier", many=True)
7593
new_partners = PartnerSerializer(source="partner", many=True)
7694
combined_suppliers = SupplierSerializer(many=True)
95+
metadata = ProductMetadataSerializer(many=True, read_only=True)
7796

7897
class Meta:
7998
primary = "products"
8099
prefetches = {
81100
"new_categories": "category",
82-
"new_main_suppliers": "supplier",
83-
"new_backup_suppliers": "backup_supplier",
101+
"new_main_suppliers": ["supplier", "supplier__metadata"],
102+
"new_backup_suppliers": ["backup_supplier", "backup_supplier__metadata"],
84103
"new_partners": "partners",
85104
# These can be defined to always load them, else they will be
86105
# copied over form all sources or selected sources only.
87106
"combined_suppliers": {
88-
"suppliers": ["supplier"],
89-
"backup_supplier": ["backup_supplier"],
107+
"suppliers": ["supplier", "supplier__metadata"],
108+
"backup_supplier": ["backup_supplier", "backup_supplier__metadata"],
90109
},
110+
"metadata": "metadata",
91111
}

tests/test_products_api.py

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
from rest_framework.settings import api_settings
88

99
from drf_sideloading.serializers import SideLoadableSerializer
10-
from tests.models import Category, Supplier, Product, Partner
10+
from tests.models import Category, Supplier, Product, Partner, ProductMetadata, SupplierMetadata
1111
from tests.serializers import (
1212
ProductSerializer,
1313
CategorySerializer,
1414
SupplierSerializer,
1515
PartnerSerializer,
16+
ProductMetadataSerializer,
1617
)
1718
from tests.viewsets import ProductViewSet
1819

@@ -32,27 +33,45 @@ def setUpClass(cls):
3233
def setUp(self):
3334
self.category = Category.objects.create(name="Category")
3435
self.supplier1 = Supplier.objects.create(name="Supplier1")
36+
self.supplier_metadata_1 = SupplierMetadata.objects.create(
37+
supplier=self.supplier1, properties="Supplier1 metadata"
38+
)
3539
self.supplier2 = Supplier.objects.create(name="Supplier2")
40+
self.supplier_metadata_2 = SupplierMetadata.objects.create(
41+
supplier=self.supplier2, properties="Supplier2 metadata"
42+
)
3643
self.supplier3 = Supplier.objects.create(name="Supplier3")
44+
self.supplier_metadata_3 = SupplierMetadata.objects.create(
45+
supplier=self.supplier3, properties="Supplier3 metadata"
46+
)
3747
self.supplier4 = Supplier.objects.create(name="Supplier4")
48+
self.supplier_metadata_4 = SupplierMetadata.objects.create(
49+
supplier=self.supplier4, properties="Supplier4 metadata"
50+
)
3851
self.partner1 = Partner.objects.create(name="Partner1")
3952
self.partner2 = Partner.objects.create(name="Partner2")
4053
self.partner3 = Partner.objects.create(name="Partner3")
4154
self.partner4 = Partner.objects.create(name="Partner4")
4255

4356
self.product1 = Product.objects.create(name="Product1", category=self.category, supplier=self.supplier1)
57+
self.product1_metadata = ProductMetadata.objects.create(product=self.product1, properties="value 1")
4458
self.product1.partners.add(self.partner1)
4559
self.product1.partners.add(self.partner2)
4660
self.product1.partners.add(self.partner4)
4761
self.product1.save()
4862

4963
self.product2 = Product.objects.create(name="Product2", category=self.category, supplier=self.supplier2)
50-
self.product1.partners.add(self.partner2)
51-
self.product1.save()
64+
self.product2_metadata = ProductMetadata.objects.create(product=self.product2, properties="value 2")
65+
self.product2.partners.add(self.partner2)
66+
self.product2.save()
67+
5268
self.product3 = Product.objects.create(name="Product3", category=self.category, supplier=self.supplier3)
53-
self.product1.partners.add(self.partner3)
54-
self.product1.save()
69+
self.product3_metadata = ProductMetadata.objects.create(product=self.product3, properties="value 3")
70+
self.product3.partners.add(self.partner3)
71+
self.product3.save()
72+
5573
self.product4 = Product.objects.create(name="Product4", category=self.category, supplier=self.supplier4)
74+
self.product4_metadata = ProductMetadata.objects.create(product=self.product4, properties="value 4")
5675

5776

5877
###################################
@@ -68,13 +87,16 @@ class TempProductSideloadableSerializer(SideLoadableSerializer):
6887
categories = CategorySerializer(source="category", many=True)
6988
suppliers = SupplierSerializer(source="supplier", many=True)
7089
partners = PartnerSerializer(many=True)
90+
partners = PartnerSerializer(many=True)
91+
metadata = ProductMetadataSerializer(many=True)
7192

7293
class Meta:
7394
primary = "products"
7495
prefetches = {
7596
"categories": "category",
76-
"suppliers": "supplier",
97+
"suppliers": ["supplier", "supplier__metadata"],
7798
"partners": "partners",
99+
"metadata": "metadata",
78100
}
79101

80102
ProductViewSet.sideloading_serializer_class = TempProductSideloadableSerializer
@@ -89,11 +111,39 @@ def test_list(self):
89111
def test_list_sideloading(self):
90112
"""Test sideloading for all defined relations"""
91113
response = self.client.get(
92-
path=reverse("product-list"), data={"sideload": "categories,suppliers,partners"}, **self.DEFAULT_HEADERS
114+
path=reverse("product-list"),
115+
data={"sideload": "categories,suppliers,partners,metadata"},
116+
**self.DEFAULT_HEADERS,
93117
)
94118
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
95119
self.assertIsInstance(response.json(), dict)
96-
self.assertListEqual(["products", "categories", "suppliers", "partners"], list(response.json().keys()))
120+
self.assertListEqual(
121+
["products", "categories", "suppliers", "partners", "metadata"], list(response.json().keys())
122+
)
123+
124+
def test_list_sideloading_with_direct_missing_one_to_one_relation(self):
125+
"""Test sideloading for all defined relations"""
126+
ProductMetadata.objects.all().delete()
127+
response = self.client.get(
128+
path=reverse("product-list"),
129+
data={"sideload": "metadata"},
130+
**self.DEFAULT_HEADERS,
131+
)
132+
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
133+
self.assertIsInstance(response.json(), dict)
134+
self.assertListEqual(["products", "metadata"], list(response.json().keys()))
135+
136+
def test_list_sideloading_with_indirect_missing_one_to_one_relation(self):
137+
"""Test sideloading for all defined relations"""
138+
SupplierMetadata.objects.all().delete()
139+
response = self.client.get(
140+
path=reverse("product-list"),
141+
data={"sideload": "suppliers"},
142+
**self.DEFAULT_HEADERS,
143+
)
144+
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
145+
self.assertIsInstance(response.json(), dict)
146+
self.assertListEqual(["products", "suppliers"], list(response.json().keys()))
97147

98148
def test_list_partial_sideloading(self):
99149
"""Test sideloading for selected relations"""
@@ -108,22 +158,48 @@ def test_detail(self):
108158
response = self.client.get(path=reverse("product-detail", args=[self.product1.id]), **self.DEFAULT_HEADERS)
109159
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
110160
self.assertIsInstance(response.json(), dict)
111-
self.assertListEqual(["name", "category", "supplier", "partners"], list(response.json().keys()))
161+
self.assertListEqual(["name", "category", "supplier", "partners", "metadata"], list(response.json().keys()))
112162
# TODO: check details
113163

114164
def test_detail_sideloading(self):
115165
"""Test sideloading for all defined relations in detail view"""
116166
response = self.client.get(
117167
path=reverse("product-detail", args=[self.product1.id]),
118-
data={"sideload": "categories,suppliers,partners"},
168+
data={"sideload": "categories,suppliers,partners,metadata"},
119169
**self.DEFAULT_HEADERS,
120170
)
121171
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
122172
self.assertIsInstance(response.json(), dict)
123-
self.assertListEqual(["products", "categories", "suppliers", "partners"], list(response.json().keys()))
173+
self.assertListEqual(
174+
["products", "categories", "suppliers", "partners", "metadata"], list(response.json().keys())
175+
)
124176
self.assertEqual(1, len(response.json().get("products")))
125177
# TODO: check details
126178

179+
def test_detail_sideloading_with_direct_missing_one_to_one_relation(self):
180+
"""Test sideloading for all defined relations"""
181+
ProductMetadata.objects.all().delete()
182+
response = self.client.get(
183+
path=reverse("product-detail", args=[self.product1.id]),
184+
data={"sideload": "metadata"},
185+
**self.DEFAULT_HEADERS,
186+
)
187+
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
188+
self.assertIsInstance(response.json(), dict)
189+
self.assertListEqual(["products", "metadata"], list(response.json().keys()))
190+
191+
def test_detail_sideloading_with_indirect_missing_one_to_one_relation(self):
192+
"""Test sideloading for all defined relations"""
193+
SupplierMetadata.objects.all().delete()
194+
response = self.client.get(
195+
path=reverse("product-detail", args=[self.product1.id]),
196+
data={"sideload": "suppliers"},
197+
**self.DEFAULT_HEADERS,
198+
)
199+
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
200+
self.assertIsInstance(response.json(), dict)
201+
self.assertListEqual(["products", "suppliers"], list(response.json().keys()))
202+
127203
def test_detail_partial_sideloading(self):
128204
"""Test sideloading for selected relations in detail view"""
129205
response = self.client.get(
@@ -940,7 +1016,7 @@ def test_detail(self):
9401016
)
9411017
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
9421018
self.assertIsInstance(response.json(), dict)
943-
self.assertListEqual(["name", "category", "supplier", "partners"], list(response.json().keys()))
1019+
self.assertListEqual(["name", "category", "supplier", "partners", "metadata"], list(response.json().keys()))
9441020

9451021

9461022
class TestDrfSideloadingBrowsableApiPermissions(BaseTestCase):
@@ -1009,7 +1085,7 @@ def test_sideloading_allow_post_without_sideloading(self):
10091085
)
10101086
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
10111087
self.assertTrue(isinstance(response.json(), dict))
1012-
self.assertListEqual(["name", "category", "supplier", "partners"], list(response.json().keys()))
1088+
self.assertListEqual(["name", "category", "supplier", "partners", "metadata"], list(response.json().keys()))
10131089

10141090
def test_sideloading_allow_post_with_sideloading(self):
10151091
# TODO: check response with new detail view sideloading logic!
@@ -1029,7 +1105,7 @@ def test_sideloading_allow_post_with_sideloading(self):
10291105
)
10301106
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
10311107
self.assertTrue(isinstance(response.json(), dict))
1032-
self.assertListEqual(["name", "category", "supplier", "partners"], list(response.json().keys()))
1108+
self.assertListEqual(["name", "category", "supplier", "partners", "metadata"], list(response.json().keys()))
10331109

10341110

10351111
class ProductSideloadSameSourceDuplicationTestCase(BaseTestCase):

0 commit comments

Comments
 (0)