django-camomilla-cms 6.0.0b14__tar.gz → 6.0.0b16__tar.gz
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.
- {django-camomilla-cms-6.0.0b14/django_camomilla_cms.egg-info → django_camomilla_cms-6.0.0b16}/PKG-INFO +2 -3
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/__init__.py +1 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/dynamic_pages_urls.py +2 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/fields/__init__.py +1 -3
- django_camomilla_cms-6.0.0b16/camomilla/managers/pages.py +31 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/model_api.py +9 -4
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/media.py +1 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/menu.py +23 -11
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/page.py +76 -38
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/openapi/schema.py +4 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/base/__init__.py +3 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/fields/__init__.py +2 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/fields/json.py +2 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/fields/related.py +5 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/mixins/__init__.py +56 -18
- django_camomilla_cms-6.0.0b16/camomilla/serializers/mixins/filter_fields.py +56 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/utils.py +3 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/validators.py +9 -5
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/settings.py +0 -4
- django_camomilla_cms-6.0.0b16/camomilla/storages/default.py +6 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/storages/optimize.py +2 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/storages/overwrite.py +2 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/defaults/parts/menu.html +1 -1
- django_camomilla_cms-6.0.0b16/camomilla/theme/__init__.py +1 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/admin.py +1 -1
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/translation.py +1 -1
- django_camomilla_cms-6.0.0b16/camomilla/utils/query_parser.py +148 -0
- django_camomilla_cms-6.0.0b16/camomilla/utils/setters.py +37 -0
- django_camomilla_cms-6.0.0b16/camomilla/views/base/__init__.py +8 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/menus.py +0 -3
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/mixins/__init__.py +9 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/mixins/pagination.py +4 -13
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16/django_camomilla_cms.egg-info}/PKG-INFO +2 -3
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/django_camomilla_cms.egg-info/SOURCES.txt +12 -6
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/django_camomilla_cms.egg-info/requires.txt +1 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/pyproject.toml +1 -2
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/setup.py +1 -1
- django_camomilla_cms-6.0.0b16/tests/fixtures/__init__.py +17 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/tests/test_api.py +2 -11
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/tests/test_camomilla_filters.py +7 -13
- django_camomilla_cms-6.0.0b16/tests/test_media.py +80 -0
- django_camomilla_cms-6.0.0b16/tests/test_model_api.py +68 -0
- django_camomilla_cms-6.0.0b16/tests/test_model_api_permissions.py +39 -0
- django_camomilla_cms-6.0.0b16/tests/test_query_parser.py +59 -0
- django_camomilla_cms-6.0.0b16/tests/test_utils.py +86 -0
- django_camomilla_cms-6.0.0b16/tests/utils/__init__.py +0 -0
- django_camomilla_cms-6.0.0b16/tests/utils/api.py +29 -0
- django-camomilla-cms-6.0.0b14/camomilla/managers/pages.py +0 -42
- django-camomilla-cms-6.0.0b14/camomilla/structured/__init__.py +0 -125
- django-camomilla-cms-6.0.0b14/camomilla/structured/cache.py +0 -202
- django-camomilla-cms-6.0.0b14/camomilla/structured/fields.py +0 -150
- django-camomilla-cms-6.0.0b14/camomilla/structured/models.py +0 -47
- django-camomilla-cms-6.0.0b14/camomilla/structured/utils.py +0 -114
- django-camomilla-cms-6.0.0b14/camomilla/theme/__init__.py +0 -1
- django-camomilla-cms-6.0.0b14/camomilla/views/base/__init__.py +0 -8
- django-camomilla-cms-6.0.0b14/tests/test_utils.py +0 -86
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/LICENSE +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/MANIFEST.in +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/README.md +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/apps.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/authentication.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/context_processors.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/contrib/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/contrib/modeltranslation/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/contrib/modeltranslation/hvad_migration.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/contrib/rest_framework/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/contrib/rest_framework/serializer.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/defaults.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/exceptions.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/fields/json.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/management/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/management/commands/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/management/commands/regenerate_thumbnails.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/managers/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/article.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/content.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/models/mixins/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/openapi/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/parsers.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/permissions.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/article.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/content_type.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/fields/file.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/media.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/menu.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/page.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/user.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/sitemap.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/storages/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/admin/camomilla/page/change_form.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/defaults/articles/default.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/defaults/base.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/defaults/pages/default.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/defaults/parts/langswitch.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates/defaults/widgets/media_select_multiple.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates_context/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates_context/autodiscover.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templates_context/rendering.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templatetags/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templatetags/camomilla_filters.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/templatetags/menus.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/apps.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/static/admin/css/responsive.css +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/static/admin/img/favicon.ico +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/static/admin/img/logo.svg +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/templates/admin/base.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/theme/templates/rosetta/base.html +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/urls.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/utils/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/utils/getters.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/utils/normalization.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/utils/seo.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/utils/templates.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/utils/translation.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/articles.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/contents.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/decorators.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/languages.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/medias.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/mixins/ordering.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/pages.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/tags.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/views/users.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/django_camomilla_cms.egg-info/dependency_links.txt +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/django_camomilla_cms.egg-info/top_level.txt +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/setup.cfg +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/tests/__init__.py +0 -0
- {django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/tests/test_models.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: django-camomilla-cms
|
3
|
-
Version: 6.0.
|
3
|
+
Version: 6.0.0b16
|
4
4
|
Summary: Django powered cms
|
5
5
|
Author-email: Lotrèk <dimmitutto@lotrek.it>
|
6
6
|
License: MIT
|
@@ -20,10 +20,9 @@ Requires-Dist: djangorestframework<4.0.0,>=3.10.0
|
|
20
20
|
Requires-Dist: django-admin-interface<1.0.0,>=0.26.0
|
21
21
|
Requires-Dist: Pillow<10.0.0,>=6.2.0
|
22
22
|
Requires-Dist: django-ckeditor<7.0.0,>=5.7.1
|
23
|
+
Requires-Dist: django-structured-json-field==0.2.0
|
23
24
|
Requires-Dist: python-magic<0.5,>=0.4
|
24
|
-
Requires-Dist: django-jsonform~=2.19.0
|
25
25
|
Requires-Dist: Django>=3.2
|
26
|
-
Requires-Dist: pydantic~=2.2.1
|
27
26
|
|
28
27
|
# camomilla django cms [](https://pypi.org/project/django-camomilla-cms)   [](./LICENSE)
|
29
28
|
|
{django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/dynamic_pages_urls.py
RENAMED
@@ -7,7 +7,8 @@ from .models import Page
|
|
7
7
|
|
8
8
|
|
9
9
|
def fetch(request, *args, **kwargs):
|
10
|
-
|
10
|
+
can_preview = request.user.is_staff or settings.DEBUG
|
11
|
+
preview = can_preview and request.GET.get("preview", False)
|
11
12
|
append_slash = getattr(django_settings, "APPEND_SLASH", True)
|
12
13
|
if append_slash and not request.path.endswith("/"):
|
13
14
|
return redirect(request.path + "/")
|
{django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/fields/__init__.py
RENAMED
@@ -1,7 +1,5 @@
|
|
1
1
|
from django.db import models
|
2
2
|
|
3
|
-
from camomilla.structured import StructuredJSONField
|
4
|
-
|
5
3
|
from .json import ArrayField, JSONField
|
6
4
|
|
7
5
|
ORDERING_ACCEPTED_FIELDS = (
|
@@ -12,4 +10,4 @@ ORDERING_ACCEPTED_FIELDS = (
|
|
12
10
|
models.SmallIntegerField,
|
13
11
|
)
|
14
12
|
|
15
|
-
__all__ = ["
|
13
|
+
__all__ = ["JSONField", "ArrayField", "ORDERING_ACCEPTED_FIELDS"]
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from django.db.models.query import QuerySet
|
2
|
+
from django.core.exceptions import ObjectDoesNotExist
|
3
|
+
from django.apps import apps
|
4
|
+
|
5
|
+
URL_NODE_RELATED_NAME = "%(app_label)s_%(class)s"
|
6
|
+
|
7
|
+
|
8
|
+
class PageQuerySet(QuerySet):
|
9
|
+
|
10
|
+
__UrlNodeModel = None
|
11
|
+
|
12
|
+
@property
|
13
|
+
def UrlNodeModel(self):
|
14
|
+
if not self.__UrlNodeModel:
|
15
|
+
self.__UrlNodeModel = apps.get_model("camomilla", "UrlNode")
|
16
|
+
return self.__UrlNodeModel
|
17
|
+
|
18
|
+
def get_permalink_kwargs(self, kwargs):
|
19
|
+
return list(set(kwargs.keys()).intersection(set(self.UrlNodeModel.LANG_PERMALINK_FIELDS + ["permalink"])))
|
20
|
+
|
21
|
+
def get(self, *args, **kwargs):
|
22
|
+
permalink_args = self.get_permalink_kwargs(kwargs)
|
23
|
+
if len(permalink_args):
|
24
|
+
try:
|
25
|
+
node = self.UrlNodeModel.objects.get(**{arg: kwargs.pop(arg) for arg in permalink_args})
|
26
|
+
kwargs["url_node"] = node
|
27
|
+
except ObjectDoesNotExist:
|
28
|
+
raise self.model.DoesNotExist(
|
29
|
+
"%s matching query does not exist." % self.model._meta.object_name
|
30
|
+
)
|
31
|
+
return super(PageQuerySet, self).get(*args, **kwargs)
|
@@ -26,6 +26,7 @@ def register(
|
|
26
26
|
"""
|
27
27
|
|
28
28
|
def inner(model):
|
29
|
+
global urlpatterns
|
29
30
|
base_meta = {
|
30
31
|
"model": model,
|
31
32
|
"fields": "__all__",
|
@@ -46,14 +47,18 @@ def register(
|
|
46
47
|
)
|
47
48
|
},
|
48
49
|
)
|
50
|
+
|
51
|
+
def get_queryset(self, *args, **kwargs):
|
52
|
+
qs = super(base_viewset, self).get_queryset(*args, **kwargs)
|
53
|
+
return qs if filters is None else qs.filter(**filters)
|
49
54
|
|
50
55
|
viewset = type(
|
51
56
|
f"{model.__name__}ViewSet",
|
52
57
|
(base_viewset,),
|
53
58
|
{
|
54
|
-
"
|
55
|
-
|
56
|
-
|
59
|
+
"queryset": model.objects.all(),
|
60
|
+
"model": model,
|
61
|
+
"get_queryset": get_queryset,
|
57
62
|
"serializer_class": serializer,
|
58
63
|
**viewset_attrs,
|
59
64
|
},
|
@@ -73,7 +78,7 @@ def register(
|
|
73
78
|
viewset,
|
74
79
|
f"{model.__name__.lower()}_api",
|
75
80
|
)
|
76
|
-
urlpatterns
|
81
|
+
urlpatterns = [path("", include(router.urls))]
|
77
82
|
return model
|
78
83
|
|
79
84
|
return inner
|
@@ -150,7 +150,7 @@ class Media(models.Model):
|
|
150
150
|
img_bytes = self.file.storage.open(self.file.name, "rb")
|
151
151
|
with Image.open(img_bytes) as orig_image:
|
152
152
|
image = orig_image.copy()
|
153
|
-
image.thumbnail((THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT), Image.
|
153
|
+
image.thumbnail((THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT), Image.LANCZOS)
|
154
154
|
|
155
155
|
# Path to save to, name, and extension
|
156
156
|
thumb_name, thumb_extension = os.path.splitext(self.file.name)
|
@@ -12,9 +12,12 @@ from pydantic import (
|
|
12
12
|
computed_field,
|
13
13
|
model_serializer,
|
14
14
|
)
|
15
|
-
from
|
16
|
-
from
|
15
|
+
from structured.pydantic.models import BaseModel
|
16
|
+
from structured.fields import StructuredJSONField
|
17
|
+
from camomilla.models.page import UrlNode, AbstractPage
|
17
18
|
from typing import Optional, Union, Callable, List
|
19
|
+
from django.db.models.base import Model as DjangoModel
|
20
|
+
from django.conf import settings
|
18
21
|
|
19
22
|
|
20
23
|
class LinkTypes(str, Enum):
|
@@ -22,21 +25,29 @@ class LinkTypes(str, Enum):
|
|
22
25
|
static = "ST"
|
23
26
|
|
24
27
|
|
25
|
-
class MenuNodeLink(
|
28
|
+
class MenuNodeLink(BaseModel):
|
26
29
|
link_type: LinkTypes = LinkTypes.static
|
27
30
|
static: str = None
|
28
|
-
content_type:
|
29
|
-
|
31
|
+
content_type: ContentType = None
|
32
|
+
page: AbstractPage = None
|
30
33
|
url_node: UrlNode = None
|
31
34
|
|
32
35
|
@model_serializer(mode="wrap", when_used="json")
|
33
36
|
def update_relational(self, handler: Callable, info: SerializationInfo):
|
34
37
|
if self.link_type == LinkTypes.relational:
|
35
|
-
if self.content_type and self.
|
36
|
-
|
38
|
+
if self.content_type and self.page:
|
39
|
+
if isinstance(self.page, DjangoModel) and not self.page._meta.abstract:
|
40
|
+
self.content_type = ContentType.objects.get_for_model(self.page.__class__)
|
41
|
+
ctype_id = getattr(self.content_type, "pk", self.content_type)
|
42
|
+
page_id = getattr(self.page, "pk", self.page)
|
43
|
+
c_type = ContentType.objects.filter(pk=ctype_id).first()
|
37
44
|
model = c_type and c_type.model_class()
|
38
|
-
page = model and model.objects.filter(pk=
|
45
|
+
page = model and model.objects.filter(pk=page_id).first()
|
39
46
|
self.url_node = page and page.url_node
|
47
|
+
elif self.url_node:
|
48
|
+
url_node_id = getattr(self.url_node, "pk", self.url_node)
|
49
|
+
self.page = UrlNode.objects.filter(pk=url_node_id).first().page
|
50
|
+
self.content_type = ContentType.objects.get_for_model(self.page.__class__)
|
40
51
|
return handler(self)
|
41
52
|
|
42
53
|
def get_url(self, request=None):
|
@@ -51,7 +62,7 @@ class MenuNodeLink(structured.BaseModel):
|
|
51
62
|
return self.get_url()
|
52
63
|
|
53
64
|
|
54
|
-
class MenuNode(
|
65
|
+
class MenuNode(BaseModel):
|
55
66
|
id: str = Field(default_factory=uuid4)
|
56
67
|
meta: dict = {}
|
57
68
|
nodes: List["MenuNode"] = []
|
@@ -63,7 +74,7 @@ class Menu(models.Model):
|
|
63
74
|
key = models.CharField(max_length=200, unique=True, editable=False)
|
64
75
|
available_classes = models.JSONField(default=dict, editable=False)
|
65
76
|
enabled = models.BooleanField(default=True)
|
66
|
-
nodes =
|
77
|
+
nodes = StructuredJSONField(default=list, schema=MenuNode)
|
67
78
|
|
68
79
|
class Meta:
|
69
80
|
verbose_name = _("menu")
|
@@ -77,7 +88,8 @@ class Menu(models.Model):
|
|
77
88
|
):
|
78
89
|
if isinstance(context, RequestContext):
|
79
90
|
context = context.flatten()
|
80
|
-
|
91
|
+
is_preview = bool(request.GET.get("preview", False))
|
92
|
+
context.update({"menu": self, "is_preview": is_preview})
|
81
93
|
return mark_safe(render_to_string(template_path, context, request))
|
82
94
|
|
83
95
|
class defaultdict(dict):
|
@@ -2,7 +2,6 @@ from typing import Sequence, Tuple
|
|
2
2
|
from uuid import uuid4
|
3
3
|
|
4
4
|
from django.core.exceptions import ObjectDoesNotExist
|
5
|
-
from django.core.validators import RegexValidator
|
6
5
|
|
7
6
|
from django.db import ProgrammingError, OperationalError, models, transaction
|
8
7
|
from django.db.models.signals import post_delete
|
@@ -13,6 +12,7 @@ from django.utils import timezone
|
|
13
12
|
from django.utils.functional import lazy
|
14
13
|
from django.utils.text import slugify
|
15
14
|
from django.utils.translation import gettext_lazy as _
|
15
|
+
from django.utils.translation import get_language
|
16
16
|
|
17
17
|
from camomilla.managers.pages import PageQuerySet
|
18
18
|
from camomilla.models.mixins import MetaMixin, SeoMixin
|
@@ -29,6 +29,12 @@ from camomilla.utils.getters import pointed_getter
|
|
29
29
|
from camomilla import settings
|
30
30
|
from camomilla.templates_context.rendering import ctx_registry
|
31
31
|
from django.conf import settings as django_settings
|
32
|
+
from modeltranslation.settings import AVAILABLE_LANGUAGES
|
33
|
+
from modeltranslation.utils import build_localized_fieldname
|
34
|
+
|
35
|
+
|
36
|
+
class UrlPathValidator():
|
37
|
+
pass
|
32
38
|
|
33
39
|
|
34
40
|
def GET_TEMPLATE_CHOICES():
|
@@ -111,6 +117,13 @@ class UrlNodeManager(models.Manager):
|
|
111
117
|
|
112
118
|
|
113
119
|
class UrlNode(models.Model):
|
120
|
+
|
121
|
+
LANG_PERMALINK_FIELDS = [
|
122
|
+
build_localized_fieldname("permalink", lang)
|
123
|
+
for lang in AVAILABLE_LANGUAGES
|
124
|
+
if settings.ENABLE_TRANSLATIONS
|
125
|
+
]
|
126
|
+
|
114
127
|
permalink = models.CharField(max_length=400, unique=True, null=True)
|
115
128
|
related_name = models.CharField(max_length=200)
|
116
129
|
objects = UrlNodeManager()
|
@@ -141,6 +154,23 @@ class UrlNode(models.Model):
|
|
141
154
|
return ""
|
142
155
|
return self.routerlink
|
143
156
|
|
157
|
+
@staticmethod
|
158
|
+
def sanitize_permalink(permalink):
|
159
|
+
if isinstance(permalink, str):
|
160
|
+
p_parts = permalink.split("/")
|
161
|
+
permalink = "/".join([slugify(p, allow_unicode=True).strip() for p in p_parts])
|
162
|
+
if not permalink.startswith("/"):
|
163
|
+
permalink = f"/{permalink}"
|
164
|
+
return permalink
|
165
|
+
|
166
|
+
def save(self, *args, **kwargs) -> None:
|
167
|
+
for lang_p_field in UrlNode.LANG_PERMALINK_FIELDS:
|
168
|
+
setattr(self, lang_p_field, UrlNode.sanitize_permalink(getattr(self, lang_p_field)))
|
169
|
+
super().save(*args, **kwargs)
|
170
|
+
|
171
|
+
def __str__(self) -> str:
|
172
|
+
return self.permalink
|
173
|
+
|
144
174
|
|
145
175
|
PAGE_CHILD_RELATED_NAME = "%(app_label)s_%(class)s_child_pages"
|
146
176
|
URL_NODE_RELATED_NAME = "%(app_label)s_%(class)s"
|
@@ -154,11 +184,29 @@ PAGE_STATUS = (
|
|
154
184
|
|
155
185
|
|
156
186
|
class PageBase(models.base.ModelBase):
|
187
|
+
"""
|
188
|
+
This models comes to implement a language based permalink logic
|
189
|
+
"""
|
190
|
+
def perm_prop_factory(permalink_field):
|
191
|
+
def getter(_self):
|
192
|
+
return getattr(_self, f"__{permalink_field}", getattr(_self.url_node or object(), permalink_field, None))
|
193
|
+
|
194
|
+
def setter(_self, value: str):
|
195
|
+
setattr(_self, f"__{permalink_field}", value)
|
196
|
+
return getter, setter
|
197
|
+
|
157
198
|
def __new__(cls, name, bases, attrs, **kwargs):
|
158
199
|
attr_meta = attrs.pop("PageMeta", None)
|
159
200
|
new_class = super().__new__(cls, name, bases, attrs, **kwargs)
|
160
201
|
page_meta = attr_meta or getattr(new_class, "PageMeta", None)
|
161
202
|
base_page_meta = getattr(new_class, "_page_meta", None)
|
203
|
+
for lang_p_field in UrlNode.LANG_PERMALINK_FIELDS:
|
204
|
+
computed_prop = property(*cls.perm_prop_factory(lang_p_field))
|
205
|
+
setattr(new_class, lang_p_field, computed_prop)
|
206
|
+
setattr(new_class, "permalink", property(
|
207
|
+
lambda _self: getattr(_self, build_localized_fieldname("permalink", get_language()), None),
|
208
|
+
lambda _self, value: setattr(_self, f"__{build_localized_fieldname('permalink', get_language())}", value)
|
209
|
+
))
|
162
210
|
if page_meta:
|
163
211
|
for name, value in getattr(base_page_meta, "__dict__", {}).items():
|
164
212
|
if name not in page_meta.__dict__:
|
@@ -167,16 +215,6 @@ class PageBase(models.base.ModelBase):
|
|
167
215
|
return new_class
|
168
216
|
|
169
217
|
|
170
|
-
class UrlPathValidator(RegexValidator):
|
171
|
-
|
172
|
-
regex = r"^[a-zA-Z0-9_\-\/]+[^\/]$"
|
173
|
-
message = _(
|
174
|
-
"Enter a valid 'slug' consisting of lowercase letters, numbers, "
|
175
|
-
"underscores, hyphens and slashes."
|
176
|
-
)
|
177
|
-
flags = 0
|
178
|
-
|
179
|
-
|
180
218
|
class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
181
219
|
date_created = models.DateTimeField(auto_now_add=True)
|
182
220
|
date_updated_at = models.DateTimeField(auto_now=True)
|
@@ -188,9 +226,7 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
188
226
|
editable=False,
|
189
227
|
)
|
190
228
|
breadcrumbs_title = models.CharField(max_length=128, null=True, blank=True)
|
191
|
-
|
192
|
-
max_length=150, null=True, blank=True, validators=[UrlPathValidator()]
|
193
|
-
)
|
229
|
+
autopermalink = models.BooleanField(default=True)
|
194
230
|
status = models.CharField(
|
195
231
|
max_length=3,
|
196
232
|
choices=PAGE_STATUS,
|
@@ -212,6 +248,19 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
212
248
|
|
213
249
|
objects = PageQuerySet.as_manager()
|
214
250
|
|
251
|
+
__cached_db_instance: "AbstractPage" = None
|
252
|
+
|
253
|
+
@property
|
254
|
+
def db_instance(self):
|
255
|
+
if self.__cached_db_instance is None:
|
256
|
+
self.__cached_db_instance = self.get_db_instance()
|
257
|
+
return self.__cached_db_instance
|
258
|
+
|
259
|
+
def get_db_instance(self):
|
260
|
+
if self.pk:
|
261
|
+
return self.__class__.objects.get(pk=self.pk)
|
262
|
+
return None
|
263
|
+
|
215
264
|
def __init__(self, *args, **kwargs):
|
216
265
|
super(AbstractPage, self).__init__(*args, **kwargs)
|
217
266
|
self._meta.get_field("template").choices = lazy(GET_TEMPLATE_CHOICES, list)()
|
@@ -240,10 +289,6 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
240
289
|
def model_info(self) -> dict:
|
241
290
|
return {"app_label": self._meta.app_label, "class": self._meta.model_name}
|
242
291
|
|
243
|
-
@property
|
244
|
-
def permalink(self) -> str:
|
245
|
-
return self.url_node and self.url_node.permalink
|
246
|
-
|
247
292
|
@property
|
248
293
|
def routerlink(self) -> str:
|
249
294
|
return self.url_node and self.url_node.routerlink
|
@@ -252,7 +297,7 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
252
297
|
def breadcrumbs(self) -> Sequence[dict]:
|
253
298
|
breadcrumb = {
|
254
299
|
"permalink": self.permalink,
|
255
|
-
"title": self.breadcrumbs_title or self.title or
|
300
|
+
"title": self.breadcrumbs_title or self.title or "",
|
256
301
|
}
|
257
302
|
if self.parent:
|
258
303
|
return self.parent.breadcrumbs + [breadcrumb]
|
@@ -291,8 +336,10 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
291
336
|
def _update_url_node(self, force: bool = False) -> UrlNode:
|
292
337
|
self.url_node = self._get_or_create_url_node()
|
293
338
|
for __ in activate_languages():
|
294
|
-
old_permalink = self.permalink
|
295
|
-
new_permalink = self.
|
339
|
+
old_permalink = self.db_instance and self.db_instance.permalink
|
340
|
+
new_permalink = self.permalink
|
341
|
+
if self.autopermalink:
|
342
|
+
new_permalink = self.generate_permalink()
|
296
343
|
force = force or old_permalink != new_permalink
|
297
344
|
set_nofallbacks(self.url_node, "permalink", new_permalink)
|
298
345
|
if force:
|
@@ -301,22 +348,10 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
301
348
|
return self.url_node
|
302
349
|
|
303
350
|
def generate_permalink(self, safe: bool = True) -> str:
|
304
|
-
|
305
|
-
if slug is None and not self.permalink:
|
306
|
-
translations = get_field_translations(self, "slug").values()
|
307
|
-
fallback_slug = next((t for t in translations if t is not None), None)
|
308
|
-
slug = (
|
309
|
-
slugify(self.title or uuid4(), allow_unicode=True)
|
310
|
-
if fallback_slug is None
|
311
|
-
else fallback_slug
|
312
|
-
)
|
313
|
-
set_nofallbacks(self, "slug", slug)
|
314
|
-
slug_parts = (slug or "").split("/")
|
315
|
-
for i, part in enumerate(slug_parts):
|
316
|
-
slug_parts[i] = slugify(part, allow_unicode=True)
|
317
|
-
permalink = "/%s" % "/".join(slug_parts)
|
351
|
+
permalink = f"/{slugify(self.title or '', allow_unicode=True)}"
|
318
352
|
if self.parent:
|
319
|
-
permalink = f"{self.parent.permalink}{permalink}"
|
353
|
+
permalink = f"/{self.parent.permalink}{permalink}"
|
354
|
+
set_nofallbacks(self, "permalink", permalink)
|
320
355
|
qs = UrlNode.objects.exclude(pk=getattr(self.url_node or object, "pk", None))
|
321
356
|
if safe and qs.filter(permalink=permalink).exists():
|
322
357
|
permalink = "/".join(
|
@@ -333,7 +368,10 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
333
368
|
def save(self, *args, **kwargs) -> None:
|
334
369
|
with transaction.atomic():
|
335
370
|
self._update_url_node()
|
336
|
-
|
371
|
+
super().save(*args, **kwargs)
|
372
|
+
self.__cached_db_instance = None
|
373
|
+
for lang_p_field in UrlNode.LANG_PERMALINK_FIELDS:
|
374
|
+
hasattr(self, f"__{lang_p_field}") and delattr(self, f"__{lang_p_field}")
|
337
375
|
|
338
376
|
@classmethod
|
339
377
|
def get(cls, request, *args, **kwargs) -> "AbstractPage":
|
@@ -386,7 +424,7 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
|
|
386
424
|
node = UrlNode.objects.get(permalink="/")
|
387
425
|
return node.page, False
|
388
426
|
except UrlNode.DoesNotExist:
|
389
|
-
return cls.get_or_create(None,
|
427
|
+
return cls.get_or_create(None, permalink="/")
|
390
428
|
|
391
429
|
@classmethod
|
392
430
|
def get_or_404(cls, request, *args, **kwargs) -> "AbstractPage":
|
@@ -55,4 +55,8 @@ class SchemaGenerator(DRFSchemaGenerator):
|
|
55
55
|
def create_view(self, callback, method, request=None):
|
56
56
|
view = super(SchemaGenerator, self).create_view(callback, method, request)
|
57
57
|
view.schema = AutoSchema()
|
58
|
+
if not hasattr(view, 'get_queryset') and getattr(view, 'queryset', None) is None:
|
59
|
+
attname = "permission_classes"
|
60
|
+
cname = "DjangoModelPermissions"
|
61
|
+
setattr(view, attname, [p for p in getattr(view, attname, []) if cname not in p.__name__])
|
58
62
|
return view
|
@@ -8,14 +8,16 @@ from ..mixins import (
|
|
8
8
|
OrderingMixin,
|
9
9
|
SetupEagerLoadingMixin,
|
10
10
|
)
|
11
|
+
from ..mixins.filter_fields import FilterFieldsMixin
|
11
12
|
|
12
13
|
|
13
14
|
class BaseModelSerializer(
|
15
|
+
SetupEagerLoadingMixin,
|
14
16
|
NestMixin,
|
17
|
+
FilterFieldsMixin,
|
15
18
|
FieldsOverrideMixin,
|
16
19
|
JSONFieldPatchMixin,
|
17
20
|
OrderingMixin,
|
18
|
-
SetupEagerLoadingMixin,
|
19
21
|
TranslationsMixin,
|
20
22
|
serializers.ModelSerializer,
|
21
23
|
):
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from django.db import models
|
2
2
|
from rest_framework import serializers
|
3
3
|
|
4
|
-
from
|
4
|
+
from structured.fields import StructuredJSONField as ModelStructuredJSONField
|
5
5
|
|
6
6
|
from .json import StructuredJSONField
|
7
7
|
from .file import FileField, ImageField
|
@@ -16,6 +16,6 @@ class FieldsOverrideMixin:
|
|
16
16
|
**serializers.ModelSerializer.serializer_field_mapping,
|
17
17
|
models.FileField: FileField,
|
18
18
|
models.ImageField: ImageField,
|
19
|
-
|
19
|
+
ModelStructuredJSONField: StructuredJSONField,
|
20
20
|
}
|
21
21
|
serializer_related_field = RelatedField
|
{django-camomilla-cms-6.0.0b14 → django_camomilla_cms-6.0.0b16}/camomilla/serializers/fields/json.py
RENAMED
@@ -3,10 +3,10 @@ from rest_framework import serializers
|
|
3
3
|
from rest_framework.utils import model_meta
|
4
4
|
from typing import TYPE_CHECKING, Any, Union, Dict, List
|
5
5
|
|
6
|
-
from camomilla.
|
6
|
+
from camomilla.utils.setters import pointed_setter
|
7
7
|
|
8
8
|
if TYPE_CHECKING:
|
9
|
-
from
|
9
|
+
from structured.pydantic.models import BaseModel
|
10
10
|
|
11
11
|
|
12
12
|
class StructuredJSONField(serializers.JSONField):
|
@@ -18,6 +18,7 @@ class RelatedField(serializers.PrimaryKeyRelatedField):
|
|
18
18
|
"""
|
19
19
|
|
20
20
|
def __init__(self, **kwargs):
|
21
|
+
self.inherited_fields_filter = kwargs.pop("inherited_fields_filter", [])
|
21
22
|
self.serializer = kwargs.pop("serializer", None)
|
22
23
|
self.lookup = kwargs.pop("lookup", "id")
|
23
24
|
if self.serializer is not None:
|
@@ -42,7 +43,10 @@ class RelatedField(serializers.PrimaryKeyRelatedField):
|
|
42
43
|
|
43
44
|
def to_representation(self, instance):
|
44
45
|
if self.serializer:
|
45
|
-
|
46
|
+
kwargs = {"context": self.context}
|
47
|
+
if self.inherited_fields_filter:
|
48
|
+
kwargs["inherited_fields_filter"] = self.inherited_fields_filter
|
49
|
+
return self.serializer(instance, **kwargs).data
|
46
50
|
return super().to_representation(instance)
|
47
51
|
|
48
52
|
def to_internal_value(self, data):
|
@@ -3,11 +3,10 @@ from django.conf import settings as django_settings
|
|
3
3
|
from django.db.models.aggregates import Max
|
4
4
|
from django.db.models.functions import Coalesce
|
5
5
|
from django.utils import translation
|
6
|
-
from modeltranslation.settings import AVAILABLE_LANGUAGES
|
7
|
-
from modeltranslation.utils import build_localized_fieldname
|
8
6
|
from rest_framework import serializers
|
9
7
|
from rest_framework.utils import model_meta
|
10
8
|
|
9
|
+
from camomilla.models import UrlNode
|
11
10
|
from camomilla.fields import ORDERING_ACCEPTED_FIELDS
|
12
11
|
from camomilla.serializers.fields.related import RelatedField
|
13
12
|
from camomilla.serializers.utils import build_standard_model_serializer
|
@@ -58,8 +57,50 @@ class SetupEagerLoadingMixin:
|
|
58
57
|
"""
|
59
58
|
This mixin allows to use the setup_eager_loading method to optimize the queries.
|
60
59
|
"""
|
61
|
-
|
62
|
-
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def optimize_qs(cls, queryset, context=None):
|
63
|
+
if hasattr(cls, "setup_eager_loading"):
|
64
|
+
queryset = cls.setup_eager_loading(queryset, context=context)
|
65
|
+
return cls.auto_optimize_queryset(queryset, context=context)
|
66
|
+
|
67
|
+
@classmethod
|
68
|
+
def auto_optimize_queryset(cls, queryset, context=None):
|
69
|
+
request = context.get("request", None)
|
70
|
+
if request and request.method == "GET":
|
71
|
+
model = getattr(cls.Meta, "model", None)
|
72
|
+
info = model_meta.get_field_info(model)
|
73
|
+
only = set()
|
74
|
+
prefetch_related = set()
|
75
|
+
select_related = set()
|
76
|
+
serializer_fields = cls(context=context).fields.keys()
|
77
|
+
filtered_fields = set()
|
78
|
+
for field in request.query_params.get("fields", "").split(","):
|
79
|
+
if "__" in field:
|
80
|
+
field, _ = field.split("__", 1)
|
81
|
+
if field in serializer_fields:
|
82
|
+
filtered_fields.add(field)
|
83
|
+
if len(filtered_fields) == 0:
|
84
|
+
filtered_fields = serializer_fields
|
85
|
+
for field in filtered_fields:
|
86
|
+
complete_field = field
|
87
|
+
if "__" in field:
|
88
|
+
field, sub_field = field.split("__", 1)
|
89
|
+
complete_field = f"{field}__{sub_field}"
|
90
|
+
if field in info.forward_relations and not info.forward_relations[field].to_many:
|
91
|
+
select_related.add(field)
|
92
|
+
only.add(complete_field)
|
93
|
+
elif field in info.reverse_relations or field in info.forward_relations and info.forward_relations[field].to_many:
|
94
|
+
prefetch_related.add(field)
|
95
|
+
only.add(complete_field)
|
96
|
+
elif field in info.fields or field == info.pk.name:
|
97
|
+
only.add(complete_field)
|
98
|
+
if len(only) > 0:
|
99
|
+
queryset = queryset.only(*only)
|
100
|
+
if len(select_related) > 0:
|
101
|
+
queryset = queryset.select_related(*select_related)
|
102
|
+
if len(prefetch_related) > 0:
|
103
|
+
queryset = queryset.prefetch_related(*prefetch_related)
|
63
104
|
return queryset
|
64
105
|
|
65
106
|
|
@@ -169,32 +210,29 @@ class AbstractPageMixin(serializers.ModelSerializer):
|
|
169
210
|
def get_breadcrumbs(self, instance: "AbstractPage"):
|
170
211
|
return instance.breadcrumbs
|
171
212
|
|
172
|
-
LANG_PERMALINK_FIELDS = [
|
173
|
-
build_localized_fieldname("permalink", lang)
|
174
|
-
for lang in AVAILABLE_LANGUAGES
|
175
|
-
if settings.ENABLE_TRANSLATIONS
|
176
|
-
]
|
177
|
-
|
178
213
|
@property
|
179
214
|
def translation_fields(self):
|
180
215
|
return super().translation_fields + ["permalink"]
|
181
216
|
|
182
217
|
def get_default_field_names(self, *args):
|
183
218
|
from camomilla.contrib.rest_framework.serializer import RemoveTranslationsMixin
|
184
|
-
|
219
|
+
default_fields = super().get_default_field_names(*args)
|
220
|
+
filtered_fields = getattr(self, "filtered_fields", [])
|
221
|
+
if len(filtered_fields) > 0:
|
222
|
+
return filtered_fields
|
185
223
|
if RemoveTranslationsMixin in self.__class__.__bases__: # noqa: E501
|
186
|
-
return
|
224
|
+
return default_fields
|
187
225
|
return (
|
188
|
-
[f for f in
|
189
|
-
+
|
190
|
-
+ ["permalink"]
|
226
|
+
[f for f in default_fields if f != "url_node"]
|
227
|
+
+ UrlNode.LANG_PERMALINK_FIELDS
|
228
|
+
+ ["permalink"]
|
191
229
|
)
|
192
230
|
|
193
231
|
def build_field(self, field_name, info, model_class, nested_depth):
|
194
|
-
if field_name in
|
232
|
+
if field_name in UrlNode.LANG_PERMALINK_FIELDS + ["permalink"]:
|
195
233
|
return serializers.CharField, {
|
196
|
-
"
|
197
|
-
"
|
234
|
+
"required": False,
|
235
|
+
"allow_blank": True,
|
198
236
|
}
|
199
237
|
return super().build_field(field_name, info, model_class, nested_depth)
|
200
238
|
|