django-camomilla-cms 6.0.0b3__py2.py3-none-any.whl → 6.0.0b4__py2.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.
camomilla/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "6.0.0-beta.3"
1
+ __version__ = "6.0.0-beta.4"
2
2
 
3
3
 
4
4
  def get_core_apps():
@@ -77,3 +77,33 @@ class TranslationsMixin(serializers.ModelSerializer):
77
77
  @property
78
78
  def is_translatable(self):
79
79
  return is_translatable(pointed_getter(self, "Meta.model"))
80
+
81
+
82
+ class RemoveTranslationsMixin(serializers.ModelSerializer):
83
+ @cached_property
84
+ def translation_fields(self):
85
+ try:
86
+ return translator.get_options_for_model(self.Meta.model).get_field_names()
87
+ except NotRegistered:
88
+ return []
89
+
90
+ def get_default_field_names(self, declared_fields, model_info):
91
+ request = self.context.get("request", False)
92
+ included_translations = request and request.GET.get(
93
+ "included_translations", False
94
+ )
95
+ if included_translations == "all":
96
+ return super().get_default_field_names(declared_fields, model_info)
97
+ elif included_translations is not False:
98
+ included_translations = included_translations.split(",")
99
+ else:
100
+ included_translations = []
101
+
102
+ field_names = super().get_default_field_names(declared_fields, model_info)
103
+ for lang in mt_settings.AVAILABLE_LANGUAGES:
104
+ if lang not in included_translations:
105
+ for field in self.translation_fields:
106
+ localized_fieldname = build_localized_fieldname(field, lang)
107
+ if localized_fieldname in field_names:
108
+ field_names.remove(localized_fieldname)
109
+ return field_names
camomilla/models/page.py CHANGED
@@ -98,14 +98,18 @@ class UrlNode(models.Model):
98
98
  def page(self) -> "AbstractPage":
99
99
  return getattr(self, self.related_name)
100
100
 
101
- @property
102
- def routerlink(self) -> str:
101
+ @staticmethod
102
+ def reverse_url(permalink: str) -> str:
103
103
  try:
104
- if self.permalink == "/":
104
+ if permalink == "/":
105
105
  return reverse("camomilla-homepage")
106
- return reverse("camomilla-permalink", args=(self.permalink.lstrip("/"),))
106
+ return reverse("camomilla-permalink", args=(permalink.lstrip("/"),))
107
107
  except NoReverseMatch:
108
- return self.permalink
108
+ return None
109
+
110
+ @property
111
+ def routerlink(self) -> str:
112
+ return self.reverse_url(self.permalink) or self.permalink
109
113
 
110
114
 
111
115
  PAGE_CHILD_RELATED_NAME = "%(app_label)s_%(class)s_child_pages"
@@ -306,7 +310,10 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
306
310
  bases += (cls.DoesNotExist,)
307
311
  message = "%s matching query does not exist." % cls._meta.object_name
308
312
  if public_error:
309
- message = "Match found: %s.\nThe page appears not to be public.\nUse ?preview=true in the url to see it." % page
313
+ message = (
314
+ "Match found: %s.\nThe page appears not to be public.\nUse ?preview=true in the url to see it."
315
+ % page
316
+ )
310
317
  raise type("PageDoesNotExist", bases, {})(message)
311
318
  return page
312
319
 
@@ -338,7 +345,11 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
338
345
  raise Http404(ex)
339
346
 
340
347
  def alternate_urls(self, *args, **kwargs) -> dict:
341
- return get_field_translations(self.url_node or object, "permalink", None)
348
+ permalinks = get_field_translations(self.url_node or object, "permalink", None)
349
+ for lang in activate_languages():
350
+ if lang in permalinks:
351
+ permalinks[lang] = UrlNode.reverse_url(permalinks[lang])
352
+ return permalinks
342
353
 
343
354
  class Meta:
344
355
  abstract = True
@@ -20,6 +20,9 @@ if django.VERSION >= (4, 0):
20
20
  else:
21
21
  from django.contrib.postgres.fields import JSONField as DjangoJSONField
22
22
 
23
+ from typing import TYPE_CHECKING
24
+ if TYPE_CHECKING:
25
+ from camomilla.models.page import AbstractPage
23
26
 
24
27
  # TODO: decide what to do with LangInfoMixin mixin!
25
28
  class LangInfoMixin(metaclass=serializers.SerializerMetaclass):
@@ -122,6 +125,16 @@ class NestMixin:
122
125
 
123
126
 
124
127
  class AbstractPageMixin(serializers.ModelSerializer):
128
+ breadcrumbs = serializers.SerializerMethodField()
129
+ routerlink = serializers.CharField(read_only=True)
130
+ template = serializers.SerializerMethodField()
131
+
132
+ def get_template(self, instance: 'AbstractPage'):
133
+ return instance.get_template_path()
134
+
135
+ def get_breadcrumbs(self, instance: 'AbstractPage'):
136
+ return instance.breadcrumbs
137
+
125
138
  LANG_PERMALINK_FIELDS = [
126
139
  build_localized_fieldname("permalink", lang)
127
140
  for lang in AVAILABLE_LANGUAGES
@@ -133,6 +146,9 @@ class AbstractPageMixin(serializers.ModelSerializer):
133
146
  return super().translation_fields + ["permalink"]
134
147
 
135
148
  def get_default_field_names(self, *args):
149
+ from camomilla.contrib.rest_framework.serializer import RemoveTranslationsMixin
150
+ if RemoveTranslationsMixin in self.__class__.__bases__: # noqa: E501
151
+ return super().get_default_field_names(*args)
136
152
  return (
137
153
  [f for f in super().get_default_field_names(*args) if f != "url_node"]
138
154
  + self.LANG_PERMALINK_FIELDS
@@ -1,6 +1,13 @@
1
+ from camomilla.models.page import UrlNode
1
2
  from camomilla.serializers.mixins import AbstractPageMixin
2
3
  from camomilla.models import Content, Page
3
4
  from camomilla.serializers.base import BaseModelSerializer
5
+ from rest_framework import serializers
6
+
7
+ from camomilla.serializers.utils import (
8
+ build_standard_model_serializer,
9
+ get_standard_bases,
10
+ )
4
11
 
5
12
 
6
13
  class ContentSerializer(BaseModelSerializer):
@@ -13,3 +20,44 @@ class PageSerializer(AbstractPageMixin, BaseModelSerializer):
13
20
  class Meta:
14
21
  model = Page
15
22
  fields = "__all__"
23
+
24
+
25
+ class BasicUrlNodeSerializer(BaseModelSerializer):
26
+ is_public = serializers.SerializerMethodField()
27
+ status = serializers.SerializerMethodField()
28
+ indexable = serializers.SerializerMethodField()
29
+
30
+ class Meta:
31
+ model = UrlNode
32
+ fields = ("id", "permalink", "status", "indexable", "is_public")
33
+
34
+ def get_is_public(self, instance: UrlNode):
35
+ return instance.page.is_public
36
+
37
+ def get_status(self, instance: UrlNode):
38
+ return instance.page.status
39
+
40
+ def get_indexable(self, instance: UrlNode):
41
+ return instance.page.indexable
42
+
43
+
44
+ class UrlNodeSerializer(BasicUrlNodeSerializer):
45
+ alternates = serializers.SerializerMethodField()
46
+
47
+ def get_alternates(self, instance: UrlNode):
48
+ return instance.page.alternate_urls()
49
+
50
+ def to_representation(self, instance: UrlNode):
51
+ model_serializer = build_standard_model_serializer(
52
+ instance.page.__class__,
53
+ depth=10,
54
+ bases=(AbstractPageMixin,) + get_standard_bases(),
55
+ )
56
+ return {
57
+ **super().to_representation(instance),
58
+ **model_serializer(instance.page, context=self.context).data,
59
+ }
60
+
61
+ class Meta:
62
+ model = UrlNode
63
+ fields = "__all__"
@@ -1,22 +1,27 @@
1
+ def get_standard_bases() -> tuple:
2
+ from rest_framework.serializers import ModelSerializer
3
+ from camomilla.serializers.fields import FieldsOverrideMixin
4
+ from camomilla.contrib.rest_framework.serializer import RemoveTranslationsMixin
5
+ from camomilla.serializers.mixins import (
6
+ JSONFieldPatchMixin,
7
+ NestMixin,
8
+ OrderingMixin,
9
+ SetupEagerLoadingMixin,
10
+ )
11
+
12
+ return (
13
+ NestMixin,
14
+ FieldsOverrideMixin,
15
+ JSONFieldPatchMixin,
16
+ OrderingMixin,
17
+ RemoveTranslationsMixin,
18
+ SetupEagerLoadingMixin,
19
+ ModelSerializer,
20
+ )
21
+
1
22
  def build_standard_model_serializer(model, depth, bases=None):
2
23
  if bases is None:
3
- from rest_framework.serializers import ModelSerializer
4
- from camomilla.serializers.fields import FieldsOverrideMixin
5
- from camomilla.serializers.mixins import (
6
- JSONFieldPatchMixin,
7
- NestMixin,
8
- OrderingMixin,
9
- SetupEagerLoadingMixin,
10
- )
11
-
12
- bases = (
13
- NestMixin,
14
- FieldsOverrideMixin,
15
- JSONFieldPatchMixin,
16
- OrderingMixin,
17
- SetupEagerLoadingMixin,
18
- ModelSerializer,
19
- )
24
+ bases = get_standard_bases()
20
25
  return type(
21
26
  f"{model.__name__}StandardSerializer",
22
27
  bases,
camomilla/settings.py CHANGED
@@ -75,6 +75,10 @@ TEMPLATE_CONTEXT_FILES = pointed_getter(
75
75
  django_settings, "CAMOMILLA.RENDER.TEMPLATE_CONTEXT_FILES", []
76
76
  )
77
77
 
78
+ STRUCTURED_FIELD_CACHE_ENABLED = pointed_getter(
79
+ django_settings, "CAMOMILLA.STRUCTURED_FIELD.CACHE_ENABLED", True
80
+ )
81
+
78
82
  DEBUG = pointed_getter(django_settings, "CAMOMILLA.DEBUG", django_settings.DEBUG)
79
83
 
80
84
  # camomilla settings example
@@ -93,6 +97,9 @@ DEBUG = pointed_getter(django_settings, "CAMOMILLA.DEBUG", django_settings.DEBUG
93
97
  # "ARTICLE": {"DEFAULT_TEMPLATE": "", "INJECT_CONTEXT": None },
94
98
  # "PAGE": {"DEFAULT_TEMPLATE": "", "INJECT_CONTEXT": None }
95
99
  # },
100
+ # "STRUCTURED_FIELD": {
101
+ # "CACHE_ENABLED": True
102
+ # }
96
103
  # "API": {"NESTING_DEPTH": 10 },
97
104
  # "DEBUG": False
98
105
  # }
@@ -2,6 +2,7 @@ from collections import defaultdict
2
2
  from inspect import isclass
3
3
  from typing import Any, Dict, Sequence
4
4
  from typing_extensions import get_args, get_origin
5
+ from camomilla.settings import STRUCTURED_FIELD_CACHE_ENABLED
5
6
  from camomilla.structured.fields import ForeignKey, QuerySet
6
7
  from camomilla.structured.models import BaseModel
7
8
  from camomilla.structured.utils import _LazyType, get_type, pointed_setter
@@ -161,6 +162,8 @@ class CacheBuilder:
161
162
  return fk_data
162
163
 
163
164
  def inject_cache(self, data: Any) -> Any:
165
+ if not STRUCTURED_FIELD_CACHE_ENABLED:
166
+ return data
164
167
  fk_data = self.get_all_fk_data(data)
165
168
  plainset = defaultdict(set)
166
169
  for model, touples in fk_data.items():
@@ -1 +1 @@
1
- __version__ = "6.0.0-beta.3"
1
+ __version__ = "6.0.0-beta.4"
camomilla/urls.py CHANGED
@@ -20,6 +20,7 @@ from camomilla.views import (
20
20
  UserViewSet,
21
21
  MenuViewSet,
22
22
  )
23
+ from camomilla.views.pages import fetch_page
23
24
 
24
25
  router = routers.DefaultRouter()
25
26
 
@@ -36,6 +37,8 @@ router.register(r"menus", MenuViewSet, "camomilla-menus")
36
37
 
37
38
  urlpatterns = [
38
39
  path("", include(router.urls)),
40
+ path("pages-router/", fetch_page),
41
+ path("pages-router/<path:permalink>", fetch_page),
39
42
  path(
40
43
  "profiles/me/", lambda _: redirect("../../users/current/"), name="profiles-me"
41
44
  ),
@@ -0,0 +1,26 @@
1
+ import functools
2
+ from django.utils.translation import activate
3
+ from django.conf import settings
4
+
5
+
6
+ def active_lang(*args, **kwargs):
7
+ def decorator(func):
8
+ @functools.wraps(func)
9
+ def wrapped_func(*args, **kwargs):
10
+ if len(args) and hasattr(args[0], "request"):
11
+ request = args[0].request
12
+ else:
13
+ request = args[0] if len(args) else kwargs.get("request", None)
14
+ lang = settings.LANGUAGE_CODE
15
+ if request and hasattr(request, "GET"):
16
+ lang = request.GET.get("lang", request.GET.get("language", lang))
17
+ if request and hasattr(request, "data"):
18
+ lang = request.data.pop("lang", request.data.pop("language", lang))
19
+ if lang and lang in [l[0] for l in settings.LANGUAGES]:
20
+ activate(lang)
21
+ request.LANGUAGE_CODE = lang
22
+ return func(*args, **kwargs)
23
+
24
+ return wrapped_func
25
+
26
+ return decorator
camomilla/views/menus.py CHANGED
@@ -1,13 +1,19 @@
1
1
  from django.contrib.contenttypes.models import ContentType
2
+ from django.db.models import Q
2
3
  from django.http import Http404
4
+ from django.shortcuts import get_object_or_404
3
5
  from rest_framework.decorators import action
4
6
  from rest_framework.response import Response
5
7
 
6
8
  from camomilla.models import AbstractPage, Menu
9
+ from camomilla.models.page import UrlNode
7
10
  from camomilla.permissions import CamomillaBasePermissions
8
11
  from camomilla.serializers import ContentTypeSerializer, MenuSerializer
12
+ from camomilla.serializers.page import BasicUrlNodeSerializer
9
13
  from camomilla.views.base import BaseModelViewset
14
+ from camomilla.views.decorators import active_lang
10
15
 
16
+ from django.utils.translation import get_language
11
17
 
12
18
  class MenuViewSet(BaseModelViewset):
13
19
  queryset = Menu.objects.all()
@@ -15,6 +21,31 @@ class MenuViewSet(BaseModelViewset):
15
21
  permission_classes = (CamomillaBasePermissions,)
16
22
  model = Menu
17
23
 
24
+ lookup_field = "key"
25
+
26
+ def get_object(self):
27
+ queryset = self.filter_queryset(self.get_queryset())
28
+ lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
29
+ assert lookup_url_kwarg in self.kwargs, (
30
+ "Expected view %s to be called with a URL keyword argument "
31
+ 'named "%s". Fix your URL conf, or set the `.lookup_field` '
32
+ "attribute on the view correctly."
33
+ % (self.__class__.__name__, lookup_url_kwarg)
34
+ )
35
+ filter = Q(**{self.lookup_field: self.kwargs[lookup_url_kwarg]})
36
+ if (
37
+ isinstance(self.kwargs[lookup_url_kwarg], str)
38
+ and self.kwargs[lookup_url_kwarg].isnumeric()
39
+ or isinstance(self.kwargs[lookup_url_kwarg], int)
40
+ ):
41
+ filter |= Q(pk=self.kwargs[lookup_url_kwarg])
42
+
43
+ obj = get_object_or_404(queryset, filter)
44
+ # May raise a permission denied
45
+ self.check_object_permissions(self.request, obj)
46
+
47
+ return obj
48
+
18
49
  @action(detail=False, methods=["get"], url_path="page_types")
19
50
  def page_types(self, request, *args, **kwargs):
20
51
  return Response(
@@ -42,3 +73,14 @@ class MenuViewSet(BaseModelViewset):
42
73
  )
43
74
  ]
44
75
  )
76
+
77
+ @active_lang()
78
+ @action(detail=False, methods=["get"], url_path="search_urlnode")
79
+ def search_urlnode(self, request, *args, **kwargs):
80
+ url_node = request.GET.get("q", "")
81
+ qs = UrlNode.objects.filter(permalink__icontains=url_node).order_by("permalink")
82
+ print(get_language())
83
+ return Response(BasicUrlNodeSerializer(qs, many=True).data)
84
+
85
+
86
+
camomilla/views/pages.py CHANGED
@@ -1,8 +1,14 @@
1
1
  from camomilla.models import Page
2
+ from camomilla.models.page import UrlNode
2
3
  from camomilla.permissions import CamomillaBasePermissions
3
4
  from camomilla.serializers import PageSerializer
5
+ from camomilla.serializers.page import UrlNodeSerializer
4
6
  from camomilla.views.base import BaseModelViewset
7
+ from camomilla.views.decorators import active_lang
5
8
  from camomilla.views.mixins import BulkDeleteMixin, GetUserLanguageMixin
9
+ from rest_framework.decorators import api_view
10
+ from rest_framework.response import Response
11
+ from django.shortcuts import get_object_or_404
6
12
 
7
13
 
8
14
  class PageViewSet(GetUserLanguageMixin, BulkDeleteMixin, BaseModelViewset):
@@ -10,3 +16,10 @@ class PageViewSet(GetUserLanguageMixin, BulkDeleteMixin, BaseModelViewset):
10
16
  serializer_class = PageSerializer
11
17
  permission_classes = (CamomillaBasePermissions,)
12
18
  model = Page
19
+
20
+
21
+ @active_lang()
22
+ @api_view(["GET"])
23
+ def fetch_page(request, permalink=""):
24
+ node = get_object_or_404(UrlNode, permalink=f"/{permalink}")
25
+ return Response(UrlNodeSerializer(node, context={"request": request}).data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-camomilla-cms
3
- Version: 6.0.0b3
3
+ Version: 6.0.0b4
4
4
  Summary: Django powered cms
5
5
  Home-page: https://github.com/lotrekagency/camomilla
6
6
  Author: Lotrèk
@@ -1,4 +1,4 @@
1
- camomilla/__init__.py,sha256=JM4pHKLcxSkpkhuX74XhGAfvaUu9EPoc4RPDMsCrR4Q,110
1
+ camomilla/__init__.py,sha256=wVhoGvi01rvXZOw0ziUQNg1TXbgdk1Z-4cFT16iGgj4,110
2
2
  camomilla/admin.py,sha256=lfQqY_puhUkTXDQWGbhX9a0hosMo6UlX3K-BvgB-2a4,2404
3
3
  camomilla/apps.py,sha256=hjfJBL47JqX3Z8D2Okzmw0jtbVPAInB2fYQVNzszyko,605
4
4
  camomilla/authentication.py,sha256=jz6tQT4PPEu-_JLox1LZrOy7EiWBb9MWaObK63MJGus,855
@@ -9,14 +9,14 @@ camomilla/exceptions.py,sha256=gLniAsK_pmsNNKGMv5Z384LXVbM8oeHcOwz4F91u1LY,111
9
9
  camomilla/model_api.py,sha256=VC3tNQucS3-KVtdZNWkkbkJn8vtl_cBKYTcC3QU6PpU,2253
10
10
  camomilla/parsers.py,sha256=fL8XGCGPxJIZNZkPdGtnPSbDP-6-yzGOCVMuLPjkx9Y,1975
11
11
  camomilla/permissions.py,sha256=9NlBO4JMmg36vXCUjPNyq6uZxhkdrnXyIbJVLtWhGWE,1813
12
- camomilla/settings.py,sha256=EO_ETpTRm9u0HI7luKIu3Nm2Fnj4JKycxSGduECzVYw,3104
12
+ camomilla/settings.py,sha256=T9lJB8qagQ1lLknmrFA-Mo46yxZbZuPhevd3IBE-D7Y,3294
13
13
  camomilla/translation.py,sha256=IDoC48xhH49lFAbOq19kOskgjECv4kRCm7bEI80jOL4,1260
14
- camomilla/urls.py,sha256=vPgldNs3b1WftY6uKyCO0ujUQy_q9SBXDqmyVIQ2onQ,2078
14
+ camomilla/urls.py,sha256=YFUYcPuvnNSTnfJa_JByRWAPLgc4_R4LgqCMrmkbFpE,2217
15
15
  camomilla/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  camomilla/contrib/modeltranslation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  camomilla/contrib/modeltranslation/hvad_migration.py,sha256=e4628zm8Z1VYOuqheLg4aD_NF8gqtkQDxpTmdtDid2o,4882
18
18
  camomilla/contrib/rest_framework/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- camomilla/contrib/rest_framework/serializer.py,sha256=afqRVbCZq_EFvOqGmqiwH7Iv3SHthDUgsWR43TZWcGE,2834
19
+ camomilla/contrib/rest_framework/serializer.py,sha256=3Hmzl2F6lpfUzEfN4lXypgNbKEUdWcer9Et8VMy_2Fo,4105
20
20
  camomilla/fields/__init__.py,sha256=VTCKK0PsJxpcgWrcqPYtWaSFhOOO2ZL56UIdla2IxF8,400
21
21
  camomilla/fields/json.py,sha256=tWEDn6kwTP6pNB53djxuVPu2d57m9cIDc4ccCEfUbDQ,1938
22
22
  camomilla/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -27,7 +27,7 @@ camomilla/models/article.py,sha256=LgkZgRsubtDV6NwBz8E2bIgKD6H3I-1QLAxEan5TYYs,1
27
27
  camomilla/models/content.py,sha256=mIgtifb_WMIt58we5u6qWZemHvuDN1zZaBeCyzHL78A,956
28
28
  camomilla/models/media.py,sha256=7TD_0nhNoi8P-Gmsr0Kag4eGaxMXuTfQOFl53Mb03cQ,6854
29
29
  camomilla/models/menu.py,sha256=GdywN50yp7ezXzy8SF8P-W3ejey31ZPlJYp2cEM38Uk,2835
30
- camomilla/models/page.py,sha256=tZqhB8ouMC5Imegxg0Paqg4I-VRCljYtUA-j138Tr0c,13024
30
+ camomilla/models/page.py,sha256=25KnH1SRXtM2hzX6Sv-8MW8XgIWCcB4AQWhRy4l_FKQ,13375
31
31
  camomilla/models/mixins/__init__.py,sha256=c2NixqvrIX4E9WGRqQbylXlqBWDXEqN9mzs_dpB0hFQ,1248
32
32
  camomilla/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  camomilla/openapi/schema.py,sha256=Drua3rV_ME4nGWvqe-ZwuABnheTaUyB4Io7z3cCmSCM,2116
@@ -36,21 +36,21 @@ camomilla/serializers/article.py,sha256=pYVcS0KztzjzSqgruElQMMEZcqTzmQUqXrdv_Sx5
36
36
  camomilla/serializers/content_type.py,sha256=qB2wkmkvQI6LHxfSI6auEh6M9cJRFBaHnpmkBCCzeYo,557
37
37
  camomilla/serializers/media.py,sha256=H4JVpRVxXVmn_BiqrjihKXpfLm9fLmHDFIICRDGJU4s,1940
38
38
  camomilla/serializers/menu.py,sha256=TdoyXs40PqxNevnRbBbYOOX9rUv9zQGiHFNduspaZnw,552
39
- camomilla/serializers/page.py,sha256=Iq85W3F-QPziz9Gb69kOqQBgak23GvG0zrJtAk7UGhw,404
39
+ camomilla/serializers/page.py,sha256=NNjEypVYu_9iKqdHV_-61ea37gxiHlDP5gsloV_i6yg,1834
40
40
  camomilla/serializers/user.py,sha256=CzrHiVRvYYWNE4eNpCNKtJB7DjVqHHwIcP4NUBXMHSo,3706
41
- camomilla/serializers/utils.py,sha256=e3JoJ4kNI4jLBzQPNoNqXYRHAaANbvAj9Kufy-VYc1o,875
41
+ camomilla/serializers/utils.py,sha256=FgO6Eov6rtrLwuZT0QWGSSvLeMmDm6gYK7uFON6qP1c,1000
42
42
  camomilla/serializers/validators.py,sha256=QtlmGyJiKaKyMBqBZ1W2VAjCoLi1vhPUnLOo7DvZpsM,1775
43
43
  camomilla/serializers/base/__init__.py,sha256=RTEHkJttqlxZjKpD75kTYIH42wlBtQI8hhPPb8r-NLw,488
44
44
  camomilla/serializers/fields/__init__.py,sha256=6JX3Dt4mmVXEQy2XN48zzuKyOQOfPgAhBdH6AeED0kk,528
45
45
  camomilla/serializers/fields/file.py,sha256=QRSPhEAB_snT0IyjtKZQk8bKKHmT9hMNB9udzbc_nVw,648
46
46
  camomilla/serializers/fields/json.py,sha256=5bTAODaTzFj_B9w-BN2c2iXoUF0hrnOz-dzebkZN4TQ,968
47
47
  camomilla/serializers/fields/related.py,sha256=Y2SnGWGDAUr3H-Ku7_YQYzbEIXUlsFqw69NCGVEpxSU,4402
48
- camomilla/serializers/mixins/__init__.py,sha256=yE5vGdeV6lvP0svLw1QzLowcuEAcN3PKas0z7x3Pydo,5501
48
+ camomilla/serializers/mixins/__init__.py,sha256=WHtxyux5CTnpwwWq-zto7K0-GgE1RHTzUC_pKgkLxas,6193
49
49
  camomilla/storages/__init__.py,sha256=ytGgX59Ar8vFfYz7eV8z-j5yO_5FqxdZM25iyLnJuSA,131
50
50
  camomilla/storages/optimize.py,sha256=WPFAkMCXub6u68kNsZKpbeqTPDqRlNef534C0DSuOws,2007
51
51
  camomilla/storages/overwrite.py,sha256=CO_zSZxr321eohYFuzPjDMK7WMFnvvwlIigIPabU_eE,343
52
52
  camomilla/structured/__init__.py,sha256=85GQW6KtzgBQVZlbNHbmkzDqjvK1zglXvuFpv_-JJcU,4163
53
- camomilla/structured/cache.py,sha256=zfZGM7aaRhBp0utYISO4z73CviZ5lUREs5IGLs1D2_k,7456
53
+ camomilla/structured/cache.py,sha256=SJSefLcB86Axvpj8xB9O_IJA2G7jmYhZmbjYR80fgJ8,7589
54
54
  camomilla/structured/fields.py,sha256=Pd9J9yxiHmB4xJqlpAQQB_gZqkVPJiIh0aXexJhsfY0,5295
55
55
  camomilla/structured/models.py,sha256=us03rOU2VtdhH4MMHIGkb11Wr6ItxPmB7ZUL1QepWmg,1790
56
56
  camomilla/structured/utils.py,sha256=h-cfkyGyBKZjZFA53UBbTA7nHAoCN1iKIJBz0ka5_pg,3446
@@ -64,7 +64,7 @@ camomilla/templates/defaults/widgets/media_select_multiple.html,sha256=k2XYou8Kk
64
64
  camomilla/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  camomilla/templatetags/camomilla_filters.py,sha256=iOk0sDkdKz5pRuRCocwd_oelaqETAla1kS3siV8ciEE,513
66
66
  camomilla/templatetags/menus.py,sha256=pLFeJ1UAm3flsU9TNo2iQk4otSwZuJPr86Nf408dZ-8,862
67
- camomilla/theme/__init__.py,sha256=rppO1EEMRDGqnCGgpzQB2oFPzzqXtzfpvcjdpHgbSBg,29
67
+ camomilla/theme/__init__.py,sha256=PN8A2DB_Z51bzNjN_K5b4hSZNT8fYVdu5odxsFxn7Vg,29
68
68
  camomilla/theme/admin.py,sha256=gDSPLAIomp2PqYMb-xNrt-O1rxxTJjHVs4p6Z9G1kpU,2468
69
69
  camomilla/theme/apps.py,sha256=_DXntnVQoASOjta2L7_nvTPBXIACASISDITxIGj5rGs,1257
70
70
  camomilla/theme/static/admin/css/responsive.css,sha256=yGq6qXrr8xEVsXTnprIBgkX-sMGZrNf0Kkh-xDxf6yE,157
@@ -83,10 +83,11 @@ camomilla/utils/translation.py,sha256=keld4EWIuMRWOuvnPGs2yGPsU5rln9WxAiA-Y_fqag
83
83
  camomilla/views/__init__.py,sha256=94QuOnnbfMMb17mruO2ydUt286-8zBmDxEPWrJv5Wog,178
84
84
  camomilla/views/articles.py,sha256=qGxebOA5iTbGGe9PfbH40YBoDPKktH8FJongg6rh2R8,571
85
85
  camomilla/views/contents.py,sha256=JxvnmgeK8JEmCMLzVG8pVq2DwvmjXtgnIdsDnn74tA4,1205
86
+ camomilla/views/decorators.py,sha256=_YptU9Hpe-LQYDi2hztr14OVwBwDC3zTP948pqA2vb8,978
86
87
  camomilla/views/languages.py,sha256=Rt_X7s3dbDBv4dxsQ9fnav_u0TAzzo8fGKBBx3esDsg,441
87
88
  camomilla/views/medias.py,sha256=S4Ak4JI6XCSu3BCZx8KOotX7TBfrIU82GPXgyP3KcZA,3001
88
- camomilla/views/menus.py,sha256=-SbnforcsjppFgT8l5EgdvzcIKA91BnrR_gMG3jPXCc,1724
89
- camomilla/views/pages.py,sha256=l8A_IA_zBOyNJDdzyz0-ePbCcjZOpVNCsQuPOWIWvLY,485
89
+ camomilla/views/menus.py,sha256=8ddc4ezGvuOgYkC5aElWpPOUIELbCFZ32O2c7-aKD_U,3408
90
+ camomilla/views/pages.py,sha256=KrBsKT0Z-rkBha8K3P6fVDt4vArQBxsc9rZ28j8XW9w,994
90
91
  camomilla/views/tags.py,sha256=XcYRlcBFSPPY32lt7POb6fWPJL_8HsTo5JcHcAOiOKw,479
91
92
  camomilla/views/users.py,sha256=_fvsKOEtep4SJLvMva2_q-HdLQT_1KlFNt4wcl3xCJk,3130
92
93
  camomilla/views/base/__init__.py,sha256=S7KGhVzHM7f0j8XD7cbBY5__66zvKYkphRD9cfl0O1E,222
@@ -99,8 +100,8 @@ tests/test_camomilla_filters.py,sha256=_W9CcwsEyewMBvnNYKk4CVqrkXxRYejle3mjiBS7h
99
100
  tests/test_models.py,sha256=WJs8lxWZWn1l7X3a_QFVc8fF5LHTsI8bc3uhQe6-o-Q,684
100
101
  tests/test_utils.py,sha256=0tdEDBaBkyjAXpbqP0SpFcfgO56MV2TWZmk9xpjR7J0,3613
101
102
  tests/urls.py,sha256=yCnalWqGClQOCrrbHtIj175aC1ufE6QfhSqT0aoWyjA,562
102
- django_camomilla_cms-6.0.0b3.dist-info/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
103
- django_camomilla_cms-6.0.0b3.dist-info/METADATA,sha256=ALk9Lz0Z6BafaO8YkMK0kF_mgrR9EAyl343F9b3TgAk,2423
104
- django_camomilla_cms-6.0.0b3.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
105
- django_camomilla_cms-6.0.0b3.dist-info/top_level.txt,sha256=G9VIGBmMMqC7JEckoTgXKmC6T2BR75QRkqRnngw1_lo,16
106
- django_camomilla_cms-6.0.0b3.dist-info/RECORD,,
103
+ django_camomilla_cms-6.0.0b4.dist-info/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
104
+ django_camomilla_cms-6.0.0b4.dist-info/METADATA,sha256=A2xAcnCXQr50lGJVZ2wbn0lpVv-UgHhDl2g-5oQl_yk,2423
105
+ django_camomilla_cms-6.0.0b4.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
106
+ django_camomilla_cms-6.0.0b4.dist-info/top_level.txt,sha256=G9VIGBmMMqC7JEckoTgXKmC6T2BR75QRkqRnngw1_lo,16
107
+ django_camomilla_cms-6.0.0b4.dist-info/RECORD,,