Skip to content

Commit 569c302

Browse files
authored
feat: Remove PlaceholderRelationSerializer and add Placeholder content instead (#73)
* feat: Remove distinction between PlaceholderRelationSerializer and PlaceholderSerializer * fix: Preview placeholders not shown * fix: Typde definitions * fix: Placeholder serializer copied admin GET params * fix: Add schema for placeholder content and tests that the open api schema is correct * Update coverage base for test setup
1 parent 2a129da commit 569c302

File tree

6 files changed

+366
-76
lines changed

6 files changed

+366
-76
lines changed

djangocms_rest/serializers/pages.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from rest_framework import serializers
77

8-
from djangocms_rest.serializers.placeholders import PlaceholderRelationSerializer
8+
from djangocms_rest.serializers.placeholders import PlaceholderSerializer
99
from djangocms_rest.utils import get_absolute_frontend_url
1010

1111

@@ -131,7 +131,7 @@ def to_representation(self, page_content: PageContent) -> dict:
131131

132132

133133
class PageContentSerializer(BasePageSerializer, BasePageContentMixin):
134-
placeholders = PlaceholderRelationSerializer(many=True, required=False)
134+
placeholders = PlaceholderSerializer(many=True, required=False)
135135

136136
def __init__(self, *args, **kwargs):
137137
super().__init__(*args, **kwargs)
@@ -142,19 +142,9 @@ def to_representation(self, page_content: PageContent) -> dict:
142142
placeholders = [
143143
placeholder for placeholder in page_content.placeholders.all() if placeholder.slot in declared_slots
144144
]
145-
146-
placeholders_data = [
147-
{
148-
"content_type_id": placeholder.content_type_id,
149-
"object_id": placeholder.object_id,
150-
"slot": placeholder.slot,
151-
}
152-
for placeholder in placeholders
153-
]
154-
155145
data = self.get_base_representation(page_content)
156-
data["placeholders"] = PlaceholderRelationSerializer(
157-
placeholders_data,
146+
data["placeholders"] = PlaceholderSerializer(
147+
placeholders,
158148
language=page_content.language,
159149
many=True,
160150
context={"request": self.request},
Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from urllib.parse import urlencode
2+
13
from django.template import Context
24
from django.urls import reverse
35

@@ -6,77 +8,85 @@
68
from djangocms_rest.serializers.utils.render import render_html
79
from djangocms_rest.utils import get_absolute_frontend_url
810

11+
try:
12+
from drf_spectacular.utils import extend_schema_field
13+
14+
HAS_SPECTACULAR = True
15+
except ImportError: # pragma: no cover
16+
HAS_SPECTACULAR = False
17+
18+
def extend_schema_field(field_schema):
19+
def decorator(field):
20+
return field
21+
22+
return decorator
23+
924

1025
class PlaceholderSerializer(serializers.Serializer):
1126
slot = serializers.CharField()
1227
label = serializers.CharField()
1328
language = serializers.CharField()
14-
content = serializers.ListSerializer(child=serializers.JSONField(), allow_empty=True, required=False)
29+
30+
# Annotate the content field for OpenAPI schema generation
31+
@extend_schema_field(
32+
{
33+
"type": "array",
34+
"items": {"type": "object"},
35+
"description": "List of serialized plugin data for this placeholder",
36+
}
37+
)
38+
class ContentField(serializers.ListSerializer):
39+
child = serializers.JSONField()
40+
41+
content = ContentField(allow_empty=True, required=False)
42+
details = serializers.URLField()
1543
html = serializers.CharField(default="", required=False)
1644

1745
def __init__(self, *args, **kwargs):
18-
request = kwargs.pop("request", None)
19-
placeholder = kwargs.pop("instance", None)
20-
language = kwargs.pop("language", None)
21-
render_plugins = kwargs.pop("render_plugins", True)
46+
self.request = kwargs.pop("request", None)
47+
self.language = kwargs.pop("language", None)
48+
self.render_plugins = kwargs.pop("render_plugins", True)
2249
super().__init__(*args, **kwargs)
23-
if request is None:
24-
request = self.context.get("request")
50+
if self.request is None:
51+
self.request = self.context.get("request")
2552

26-
if placeholder and request and language:
27-
if render_plugins:
53+
def to_representation(self, instance):
54+
instance.label = instance.get_label()
55+
instance.language = self.language
56+
instance.details = self.get_details(instance)
57+
if instance and self.request and self.language:
58+
if self.render_plugins:
2859
from djangocms_rest.plugin_rendering import RESTRenderer
2960

30-
renderer = RESTRenderer(request)
31-
placeholder.content = renderer.serialize_placeholder(
32-
placeholder,
33-
context=Context({"request": request}),
34-
language=language,
61+
renderer = RESTRenderer(self.request)
62+
instance.content = renderer.serialize_placeholder(
63+
instance,
64+
context=Context({"request": self.request}),
65+
language=self.language,
3566
use_cache=True,
3667
)
37-
if request.GET.get("html", False):
38-
html = render_html(request, placeholder, language)
68+
if self.request.GET.get("html", False):
69+
html = render_html(self.request, instance, self.language)
3970
for key, value in html.items():
40-
if not hasattr(placeholder, key):
41-
setattr(placeholder, key, value)
42-
self.fields[key] = serializers.CharField()
43-
placeholder.label = placeholder.get_label()
44-
placeholder.language = language
45-
self.instance = placeholder
71+
if not hasattr(instance, key):
72+
setattr(instance, key, value)
4673

47-
48-
class PlaceholderRelationSerializer(serializers.Serializer):
49-
content_type_id = serializers.IntegerField()
50-
object_id = serializers.IntegerField()
51-
slot = serializers.CharField()
52-
details = serializers.URLField()
53-
54-
def __init__(self, *args, **kwargs):
55-
language = kwargs.pop("language", None)
56-
super().__init__(*args, **kwargs)
57-
self.request = self.context.get("request")
58-
self.language = language
59-
60-
def to_representation(self, instance):
61-
instance["details"] = self.get_details(instance)
6274
return super().to_representation(instance)
6375

6476
def get_details(self, instance):
65-
api_endpoint = get_absolute_frontend_url(
77+
url = get_absolute_frontend_url(
6678
self.request,
6779
reverse(
6880
"placeholder-detail",
6981
args=[
7082
self.language,
71-
instance.get("content_type_id"),
72-
instance.get("object_id"),
73-
instance.get("slot"),
83+
instance.content_type_id,
84+
instance.object_id,
85+
instance.slot,
7486
],
7587
),
7688
)
77-
if self.request._preview_mode:
78-
if "?" in api_endpoint:
79-
api_endpoint += "&preview=1"
80-
else:
81-
api_endpoint += "?preview=1"
82-
return api_endpoint
89+
get_params = {key: self.request.GET[key] for key in ("html", "preview") if key in self.request.GET}
90+
if get_params:
91+
url += "?" + urlencode(get_params)
92+
return url

tests/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def __getitem__(self, item):
181181
REST_FRAMEWORK = {
182182
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
183183
"PAGE_SIZE": 10,
184+
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
184185
}
185186

186187
USE_TZ = True

0 commit comments

Comments
 (0)