djangocms-render-context 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- __version__ = "1.0.0"
1
+ __version__ = "1.1.0"
@@ -21,6 +21,7 @@ class RenderContextPlugin(CMSPluginBase):
21
21
  _("Sources"),
22
22
  {
23
23
  "fields": (
24
+ "mimetype",
24
25
  "context",
25
26
  "file",
26
27
  (
@@ -11,10 +11,18 @@ from django.template.exceptions import TemplateSyntaxError
11
11
  from django.template.loader import get_template
12
12
  from django.utils.translation import gettext_lazy as _
13
13
  from filer.models.filemodels import File
14
+ from sekizai.context import SekizaiContext
14
15
 
15
16
  from .cache import get_cache_key
16
17
  from .exceptions import SourceParseFailure
17
- from .loaders import SUPPORTED_FILE_TYPES, get_data_from_file, get_data_from_url
18
+ from .loaders import (
19
+ CONTEXT_DATA_FORMATS,
20
+ LOADERS,
21
+ SUPPORTED_FILE_TYPES,
22
+ get_data_from_file,
23
+ get_data_from_url,
24
+ value_to_bytes,
25
+ )
18
26
 
19
27
  TEMPLATES = (("", ""),)
20
28
 
@@ -24,6 +32,11 @@ sourceType = Union[str, File] # noqa: UP007
24
32
  class RenderContextForm(ModelForm):
25
33
  """Render Context Form."""
26
34
 
35
+ mimetype = forms.ChoiceField(
36
+ label=_("Type of Data for context"),
37
+ choices=CONTEXT_DATA_FORMATS,
38
+ help_text=_("The format must be consistent with the data in the context."),
39
+ )
27
40
  template_list = forms.ChoiceField(
28
41
  label=_("Template list"),
29
42
  required=False,
@@ -51,10 +64,16 @@ class RenderContextForm(ModelForm):
51
64
  except SourceParseFailure as error:
52
65
  self.add_error(name, error)
53
66
 
67
+ def check_context_data(self, value: str, mimetype: str) -> Context:
68
+ try:
69
+ return Context(LOADERS[mimetype](value_to_bytes(value, mimetype)))
70
+ except SourceParseFailure as error:
71
+ self.add_error("context", error)
72
+
54
73
  def check_context(self, cleaned_data: dict) -> Context:
55
74
  context = Context({})
56
75
  if cleaned_data["context"]:
57
- context = Context(cleaned_data["context"])
76
+ context = self.check_context_data(cleaned_data["context"], cleaned_data["mimetype"])
58
77
  elif cleaned_data["file"]:
59
78
  context = self.check_value("file", cleaned_data["file"], get_data_from_file)
60
79
  elif cleaned_data["source"]:
@@ -78,7 +97,7 @@ class RenderContextForm(ModelForm):
78
97
  template = get_template(cleaned_data["template_list"]).template
79
98
  if template:
80
99
  try:
81
- template.render(context)
100
+ template.render(SekizaiContext(context))
82
101
  except (TemplateDoesNotExist, TemplateSyntaxError) as error:
83
102
  self.add_error(field_name, error)
84
103
 
@@ -1,3 +1,5 @@
1
+ import base64
2
+ import binascii
1
3
  import csv
2
4
  import json
3
5
  import xml.etree.ElementTree as ET
@@ -47,6 +49,17 @@ def get_data_from_file(source: File) -> dataType:
47
49
  return LOADERS[source.mime_type](source.file.read())
48
50
 
49
51
 
52
+ def value_to_bytes(value: str, mimetype: str) -> bytes:
53
+ if mimetype == "application/vnd.oasis.opendocument.spreadsheet":
54
+ try:
55
+ content = base64.b64decode(value)
56
+ except (binascii.Error, ValueError) as err:
57
+ raise SourceParseFailure(err) from err
58
+ else:
59
+ content = value.encode("utf8")
60
+ return content
61
+
62
+
50
63
  def load_json(content: bytes) -> dataType:
51
64
  try:
52
65
  return json.load(BytesIO(content))
@@ -90,7 +103,7 @@ def load_spreadsheet(content: bytes) -> dataType:
90
103
  try:
91
104
  handle = zipfile.ZipFile(BytesIO(content))
92
105
  payload = handle.read("content.xml")
93
- except (zipfile.BadZipFile, KeyError) as err:
106
+ except (zipfile.BadZipFile, KeyError, ValueError) as err:
94
107
  raise SourceParseFailure(err) from err
95
108
  finally:
96
109
  if handle is None:
@@ -212,3 +225,10 @@ LOADERS = {
212
225
  "application/xml": load_xml,
213
226
  "application/vnd.oasis.opendocument.spreadsheet": load_spreadsheet,
214
227
  }
228
+ CONTEXT_DATA_FORMATS = (
229
+ ("application/json", "JSON"),
230
+ ("application/yaml", "YAML"),
231
+ ("application/xml", "XML"),
232
+ ("text/csv", "CSV"),
233
+ ("application/vnd.oasis.opendocument.spreadsheet", "ODS (in Base64)"),
234
+ )
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: PACKAGE VERSION\n"
9
9
  "Report-Msgid-Bugs-To: \n"
10
- "POT-Creation-Date: 2025-12-11 13:17+0100\n"
10
+ "POT-Creation-Date: 2026-01-09 09:26+0100\n"
11
11
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12
12
  "Last-Translator: Zdeněk Böhm <zdenek.bohm@nic.cz>\n"
13
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -25,11 +25,11 @@ msgstr ""
25
25
  "zdrojový soubor nepoužije i přesto, že je zadán."
26
26
 
27
27
  msgid ""
28
- "Context data in JSON format. They take precedence over the source file and "
29
- "source URL."
28
+ "Context data in selected format. They take precedence over the source file "
29
+ "and source URL."
30
30
  msgstr ""
31
- "Data pro kontext ve formátu JSON. Mají přednost před zdrojovým souborem a "
32
- "URL zdroje."
31
+ "Data pro kontext v nastaveném formátu. Mají přednost před zdrojovým souborem "
32
+ "a URL zdroje."
33
33
 
34
34
  msgid "Data for context"
35
35
  msgstr "Data pro kontext"
@@ -94,6 +94,9 @@ msgstr ""
94
94
  "kontext nebo Zdrojový soubor, tak se URL zdroje nepoužije i přesto, že je "
95
95
  "zadáno."
96
96
 
97
+ msgid "The format must be consistent with the data in the context."
98
+ msgstr "Formát musí odpovídat datům v kontextu."
99
+
97
100
  msgid ""
98
101
  "The time in minutes during which data will not be retrieved from the Source "
99
102
  "URL, but will remain in the cache. If set to zero, data from the source URL "
@@ -103,5 +106,8 @@ msgstr ""
103
106
  "zůstanou ponechána v cache. Je-li nastavena nula, tak se data z URL zdroje "
104
107
  "do cache neukládají, ale načítají se pokaždé."
105
108
 
109
+ msgid "Type of Data for context"
110
+ msgstr "Typ dat pro kontext"
111
+
106
112
  msgid "Unsupported file mime type: "
107
113
  msgstr "Nepodporovaný mime typ souboru: "
@@ -1,7 +1,6 @@
1
1
  # Generated by Django 5.2.8 on 2025-12-10 09:02
2
2
 
3
3
  import django.db.models.deletion
4
- import djangocms_render_context.encoders
5
4
  import filer.fields.file
6
5
  from django.db import migrations, models
7
6
 
@@ -35,7 +34,6 @@ class Migration(migrations.Migration):
35
34
  "context",
36
35
  models.JSONField(
37
36
  blank=True,
38
- encoder=djangocms_render_context.encoders.PrettyJsonEncoder,
39
37
  help_text="Context data in JSON format. They take precedence over the source file and source URL.",
40
38
  null=True,
41
39
  verbose_name="Data for context",
@@ -0,0 +1,33 @@
1
+ # Generated by Django 5.2.9 on 2026-01-09 07:40
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("djangocms_render_context", "0001_initial"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="rendercontext",
15
+ name="mimetype",
16
+ field=models.CharField(
17
+ default="application/json",
18
+ help_text="The format must be consistent with the data in the context.",
19
+ max_length=255,
20
+ verbose_name="Type of Data for context",
21
+ ),
22
+ ),
23
+ migrations.AlterField(
24
+ model_name="rendercontext",
25
+ name="context",
26
+ field=models.TextField(
27
+ blank=True,
28
+ help_text="Context data in selected format. They take precedence over the source file and source URL.",
29
+ null=True,
30
+ verbose_name="Data for context",
31
+ ),
32
+ ),
33
+ ]
@@ -5,20 +5,24 @@ from django.db import models
5
5
  from django.utils.translation import gettext_lazy as _
6
6
  from filer.fields.file import FilerFileField
7
7
 
8
- from .encoders import PrettyJsonEncoder
9
8
  from .exceptions import SourceParseFailure
10
- from .loaders import get_cached_data_from_url, get_data_from_file
9
+ from .loaders import LOADERS, get_cached_data_from_url, get_data_from_file, value_to_bytes
11
10
 
12
11
  LOGGER = logging.getLogger(__name__)
13
12
 
14
13
 
15
14
  class RenderContext(CMSPlugin):
16
- context = models.JSONField(
15
+ mimetype = models.CharField(
16
+ verbose_name=_("Type of Data for context"),
17
+ max_length=255,
18
+ default="application/json",
19
+ help_text=_("The format must be consistent with the data in the context."),
20
+ )
21
+ context = models.TextField(
17
22
  verbose_name=_("Data for context"),
18
23
  null=True,
19
24
  blank=True,
20
- encoder=PrettyJsonEncoder,
21
- help_text=_("Context data in JSON format. They take precedence over the source file and source URL."),
25
+ help_text=_("Context data in selected format. They take precedence over the source file and source URL."),
22
26
  )
23
27
  file = FilerFileField(
24
28
  verbose_name=_("Source file"),
@@ -82,7 +86,7 @@ class RenderContext(CMSPlugin):
82
86
 
83
87
  def get_data(self):
84
88
  if self.context:
85
- return self.context
89
+ return LOADERS[self.mimetype](value_to_bytes(self.context, self.mimetype))
86
90
  elif self.file:
87
91
  try:
88
92
  return get_data_from_file(self.file)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djangocms-render-context
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Render context into template.
5
5
  Author-email: Zdeněk Böhm <zdenek.bohm@nic.cz>
6
6
  License-Expression: BSD-3-Clause
@@ -26,6 +26,7 @@ Requires-Python: >=3.9
26
26
  Description-Content-Type: text/markdown
27
27
  Requires-Dist: django-cms<6,>=4.0
28
28
  Requires-Dist: django-filer~=3.4
29
+ Requires-Dist: django-sekizai~=4.1
29
30
  Requires-Dist: pyyaml
30
31
  Requires-Dist: requests
31
32
  Provides-Extra: quality
@@ -0,0 +1,17 @@
1
+ djangocms_render_context/__init__.py,sha256=LGVQyDsWifdACo7qztwb8RWWHds1E7uQ-ZqD8SAjyw4,22
2
+ djangocms_render_context/cache.py,sha256=PwagqDTqh3I83e7Ru52ei4P05juZ6Ob_pILukGGtsTo,99
3
+ djangocms_render_context/cms_plugins.py,sha256=GMtqfSyn2YM48ifgJSTJ5LyRBA0WhvIkqtF_ymMBwME,1623
4
+ djangocms_render_context/exceptions.py,sha256=r5L-U90T_60CPSagcwWmu_r6DkbHAghg04uS8OvzTPo,69
5
+ djangocms_render_context/forms.py,sha256=3gmFDTcqwXp9FNfZvIHbuSWsTzdkBuidcnGsQlX9B2o,4392
6
+ djangocms_render_context/loaders.py,sha256=s3uRG-SBhZ_vlBf01dGc3usGiyVHTrA_vvDmw80zgdQ,7400
7
+ djangocms_render_context/models.py,sha256=OqWONL6LaEeEBOgcjOk1QpeEE4qeip-FHUbdHrNWlkQ,3648
8
+ djangocms_render_context/utils.py,sha256=HmkARbCxCJ6-SNRuH7zI4BY3BBf87c9cQuwBUNId53I,1632
9
+ djangocms_render_context/locale/cs/LC_MESSAGES/django.mo,sha256=ML6jtfvv6ZzClweXXeqJmHRvWzH-iUkJozA40OkYyZ8,3126
10
+ djangocms_render_context/locale/cs/LC_MESSAGES/django.po,sha256=kn-ZDENpLYDwaooBdM50qM_oCRfjXpMb2Eo7H8Jg3Kk,3352
11
+ djangocms_render_context/migrations/0001_initial.py,sha256=tg3Wu_KMfykrQKn2kYMm_3COyheNA6mqWv3h-IxnXqk,3728
12
+ djangocms_render_context/migrations/0002_rendercontext_mimetype.py,sha256=6FHuX_5U4lHWbH37145wuPSvdPqqEgVIbdPGEXec1ck,1006
13
+ djangocms_render_context/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ djangocms_render_context-1.1.0.dist-info/METADATA,sha256=eCo5vGsqPH6I2BymyT8c2IEEa1qyZ5XbwX5f3Xc_bYk,2900
15
+ djangocms_render_context-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ djangocms_render_context-1.1.0.dist-info/top_level.txt,sha256=J82yBJeJTHoDzwzFIU3i4jFHxn3nAjgn-Fn5JSjVKQ8,25
17
+ djangocms_render_context-1.1.0.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- from django.core.serializers.json import DjangoJSONEncoder
2
-
3
-
4
- class PrettyJsonEncoder(DjangoJSONEncoder):
5
- def __init__(self, *args, **kwargs):
6
- kwargs["indent"] = 2
7
- kwargs["sort_keys"] = False
8
- super().__init__(*args, **kwargs)
@@ -1,17 +0,0 @@
1
- djangocms_render_context/__init__.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
2
- djangocms_render_context/cache.py,sha256=PwagqDTqh3I83e7Ru52ei4P05juZ6Ob_pILukGGtsTo,99
3
- djangocms_render_context/cms_plugins.py,sha256=YBNH5Rh79xdC2puO3HOLZ0R6miUDBelGd-rmPAQ2Epo,1591
4
- djangocms_render_context/encoders.py,sha256=TIIcj_6vgXlUH5D0oeozCA7ixN4WNnfrnk15bAmfpQ8,253
5
- djangocms_render_context/exceptions.py,sha256=r5L-U90T_60CPSagcwWmu_r6DkbHAghg04uS8OvzTPo,69
6
- djangocms_render_context/forms.py,sha256=bpfoWoHUZXzhobH_fekH5txXRLQIKjMsxl8n6Yi-6fs,3754
7
- djangocms_render_context/loaders.py,sha256=JUFOwXCPbRG-4J79nrIT1AiRgq_je7km5VGhnO22Uxs,6774
8
- djangocms_render_context/models.py,sha256=BmdQQi47vZjkf1vaQr7KyfeSw9tAmY0atnoNfA2AgxI,3404
9
- djangocms_render_context/utils.py,sha256=HmkARbCxCJ6-SNRuH7zI4BY3BBf87c9cQuwBUNId53I,1632
10
- djangocms_render_context/locale/cs/LC_MESSAGES/django.mo,sha256=sxF9h5d4-av6CQoVXCSIKuIw_KMyCzmKJ7N74rD0hus,2903
11
- djangocms_render_context/locale/cs/LC_MESSAGES/django.po,sha256=bQMJnXI6CkCbMfbJ56SvirX1_rJOVwFLxJjFe2tsQeE,3157
12
- djangocms_render_context/migrations/0001_initial.py,sha256=bdIs0Jl8M8JcC-i03vxp612Lim_mUJ-BOaq2D3YI6uw,3854
13
- djangocms_render_context/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- djangocms_render_context-1.0.0.dist-info/METADATA,sha256=k1wb9eo0N7fBlLk8Xm4nv5zWddbQSJRjrcsQxYwEmSA,2865
15
- djangocms_render_context-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
- djangocms_render_context-1.0.0.dist-info/top_level.txt,sha256=J82yBJeJTHoDzwzFIU3i4jFHxn3nAjgn-Fn5JSjVKQ8,25
17
- djangocms_render_context-1.0.0.dist-info/RECORD,,