django-camomilla-cms 6.0.0b11__py2.py3-none-any.whl → 6.0.0b13__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.11"
1
+ __version__ = "6.0.0-beta.13"
2
2
 
3
3
 
4
4
  def get_core_apps():
@@ -1,5 +1,5 @@
1
1
  from functools import cached_property
2
- from typing import Iterable, Union
2
+ from typing import Iterable, Union, List
3
3
  from django.http import QueryDict
4
4
 
5
5
  from modeltranslation import settings as mt_settings
@@ -33,7 +33,7 @@ def plain_to_nest(data, fields, accessor=TRANS_ACCESSOR):
33
33
  return data
34
34
 
35
35
 
36
- def nest_to_plain(data: Union[dict, QueryDict], fields: list[str], accessor=TRANS_ACCESSOR):
36
+ def nest_to_plain(data: Union[dict, QueryDict], fields: List[str], accessor=TRANS_ACCESSOR):
37
37
  """
38
38
  This function is the inverse of plain_to_nest.
39
39
  It transforms a dictionary with nested translations fields (es. {"translations": {"en": {"title": "Hello"}}})
@@ -68,7 +68,7 @@ class TranslationsMixin(serializers.ModelSerializer):
68
68
  """
69
69
 
70
70
  @cached_property
71
- def translation_fields(self) -> list[str]:
71
+ def translation_fields(self) -> List[str]:
72
72
  try:
73
73
  return translator.get_options_for_model(self.Meta.model).get_field_names()
74
74
  except NotRegistered:
@@ -0,0 +1,3 @@
1
+ from .pages import PageQuerySet
2
+
3
+ __all__ = ["PageQuerySet"]
@@ -0,0 +1,31 @@
1
+ from typing import Any, Tuple
2
+ from django.db.models.query import QuerySet
3
+ from django.db import transaction
4
+ from django.apps import apps
5
+
6
+ URL_NODE_RELATED_NAME = "%(app_label)s_%(class)s"
7
+
8
+
9
+ class PageQuerySet(QuerySet):
10
+ def get_or_create(self, defaults=None, **kwargs) -> Tuple[Any, bool]:
11
+ if "permalink" in kwargs:
12
+ with transaction.atomic():
13
+ UrlNode = apps.get_model("camomilla", "UrlNode")
14
+ url_node, created = UrlNode.objects.get_or_create(
15
+ permalink=kwargs.pop("permalink"),
16
+ related_name=URL_NODE_RELATED_NAME % self.model_info
17
+ )
18
+ if created is False and url_node.page is not None:
19
+ page = self.get(**kwargs)
20
+ if page.pk != url_node.page.pk:
21
+ raise self.model.MultipleObjectsReturned(
22
+ "got more than one %s object for the same permalink: %s"
23
+ % (
24
+ self.model._meta.object_name,
25
+ kwargs["permalink"],
26
+ )
27
+ )
28
+ return url_node.page, False
29
+ kwargs["url_node"] = url_node
30
+ return super().get_or_create(defaults, **kwargs)
31
+ return super().get_or_create(defaults, **kwargs)
camomilla/models/menu.py CHANGED
@@ -14,7 +14,7 @@ from pydantic import (
14
14
  )
15
15
  from camomilla import structured
16
16
  from camomilla.models.page import UrlNode
17
- from typing import Optional, Union, Callable
17
+ from typing import Optional, Union, Callable, List
18
18
 
19
19
 
20
20
  class LinkTypes(str, Enum):
@@ -54,7 +54,7 @@ class MenuNodeLink(structured.BaseModel):
54
54
  class MenuNode(structured.BaseModel):
55
55
  id: str = Field(default_factory=uuid4)
56
56
  meta: dict = {}
57
- nodes: list["MenuNode"] = []
57
+ nodes: List["MenuNode"] = []
58
58
  title: str = ""
59
59
  link: MenuNodeLink
60
60
 
camomilla/models/page.py CHANGED
@@ -2,6 +2,8 @@ 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
  from django.db import ProgrammingError, OperationalError, models, transaction
6
8
  from django.db.models.signals import post_delete
7
9
  from django.dispatch import receiver
@@ -12,6 +14,7 @@ from django.utils.functional import lazy
12
14
  from django.utils.text import slugify
13
15
  from django.utils.translation import gettext_lazy as _
14
16
 
17
+ from camomilla.managers.pages import PageQuerySet
15
18
  from camomilla.models.mixins import MetaMixin, SeoMixin
16
19
  from camomilla.utils import (
17
20
  activate_languages,
@@ -164,6 +167,16 @@ class PageBase(models.base.ModelBase):
164
167
  return new_class
165
168
 
166
169
 
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
+
167
180
  class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
168
181
  date_created = models.DateTimeField(auto_now_add=True)
169
182
  date_updated_at = models.DateTimeField(auto_now=True)
@@ -175,7 +188,9 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
175
188
  editable=False,
176
189
  )
177
190
  breadcrumbs_title = models.CharField(max_length=128, null=True, blank=True)
178
- slug = models.SlugField(max_length=150, allow_unicode=True, null=True, blank=True)
191
+ slug = models.CharField(
192
+ max_length=150, null=True, blank=True, validators=[UrlPathValidator()]
193
+ )
179
194
  status = models.CharField(
180
195
  max_length=3,
181
196
  choices=PAGE_STATUS,
@@ -195,6 +210,8 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
195
210
  on_delete=models.CASCADE,
196
211
  )
197
212
 
213
+ objects = PageQuerySet.as_manager()
214
+
198
215
  def __init__(self, *args, **kwargs):
199
216
  super(AbstractPage, self).__init__(*args, **kwargs)
200
217
  self._meta.get_field("template").choices = lazy(GET_TEMPLATE_CHOICES, list)()
@@ -294,7 +311,10 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
294
311
  else fallback_slug
295
312
  )
296
313
  set_nofallbacks(self, "slug", slug)
297
- permalink = "/%s" % slugify(slug or "", allow_unicode=True)
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)
298
318
  if self.parent:
299
319
  permalink = f"{self.parent.permalink}{permalink}"
300
320
  qs = UrlNode.objects.exclude(pk=getattr(self.url_node or object, "pk", None))
@@ -319,12 +339,14 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
319
339
  def get(cls, request, *args, **kwargs) -> "AbstractPage":
320
340
  bypass_type_check = kwargs.pop("bypass_type_check", False)
321
341
  bypass_public_check = kwargs.pop("bypass_public_check", False)
322
- path = request.path
323
- if getattr(django_settings, "APPEND_SLASH", True):
324
- path = path.rstrip("/")
325
342
  if len(kwargs.keys()) > 0:
326
343
  page = cls.objects.get(**kwargs)
327
344
  else:
345
+ if not request:
346
+ raise ValueError("request is required if no kwargs are passed")
347
+ path = request.path
348
+ if getattr(django_settings, "APPEND_SLASH", True):
349
+ path = path.rstrip("/")
328
350
  node = UrlNode.objects.filter(
329
351
  permalink=url_lang_decompose(path)["permalink"]
330
352
  ).first()
@@ -374,12 +396,20 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
374
396
  raise Http404(ex)
375
397
 
376
398
  def alternate_urls(self, *args, **kwargs) -> dict:
399
+ request = False
400
+ if len(args) > 0:
401
+ request = args[0]
402
+ if "request" in kwargs:
403
+ request = kwargs["request"]
404
+ preview = request and getattr(request, "GET", {}).get("preview", False)
377
405
  permalinks = get_field_translations(self.url_node or object, "permalink", None)
378
406
  for lang in activate_languages():
379
407
  if lang in permalinks:
380
408
  permalinks[lang] = (
381
- UrlNode.reverse_url(permalinks[lang]) if self.is_public else None
409
+ UrlNode.reverse_url(permalinks[lang]) if preview or self.is_public else None
382
410
  )
411
+ if preview:
412
+ permalinks = {k: f"{v}?preview=true" for k, v in permalinks.items()}
383
413
  return permalinks
384
414
 
385
415
  class Meta:
@@ -1,7 +1,7 @@
1
1
  from pydantic import TypeAdapter, ValidationError
2
2
  from rest_framework import serializers
3
3
  from rest_framework.utils import model_meta
4
- from typing import TYPE_CHECKING, Any, Union
4
+ from typing import TYPE_CHECKING, Any, Union, Dict, List
5
5
 
6
6
  from camomilla.structured.utils import pointed_setter
7
7
 
@@ -29,7 +29,7 @@ class StructuredJSONField(serializers.JSONField):
29
29
  self.json_schema = field.schema.json_schema()
30
30
  super().bind(field_name, parent)
31
31
 
32
- def to_representation(self, instance: Union["BaseModel", list["BaseModel"]]):
32
+ def to_representation(self, instance: Union["BaseModel", List["BaseModel"]]):
33
33
  if isinstance(instance, list) and self.many:
34
34
  return super().to_representation(
35
35
  self.schema.dump_python(instance, exclude_unset=True)
@@ -40,7 +40,7 @@ class StructuredJSONField(serializers.JSONField):
40
40
  try:
41
41
  return self.schema.validate_python(super().to_internal_value(data))
42
42
  except ValidationError as e:
43
- drf_error: Union[list, dict[str, Any]] = [] if self.many else {}
43
+ drf_error: Union[list, Dict[str, Any]] = [] if self.many else {}
44
44
  for error in e.errors():
45
45
  pointed_setter(
46
46
  drf_error, ".".join([str(x) for x in error["loc"]]), [error["msg"]]
@@ -161,9 +161,9 @@ class AbstractPageMixin(serializers.ModelSerializer):
161
161
 
162
162
  breadcrumbs = serializers.SerializerMethodField()
163
163
  routerlink = serializers.CharField(read_only=True)
164
- template = serializers.SerializerMethodField()
164
+ template_file = serializers.SerializerMethodField()
165
165
 
166
- def get_template(self, instance: "AbstractPage"):
166
+ def get_template_file(self, instance: "AbstractPage"):
167
167
  return instance.get_template_path()
168
168
 
169
169
  def get_breadcrumbs(self, instance: "AbstractPage"):
@@ -1,5 +1,5 @@
1
1
  import json
2
- from typing import Any, Union, TYPE_CHECKING
2
+ from typing import Any, Union, Type, TYPE_CHECKING, List
3
3
 
4
4
  from django.db.models import JSONField
5
5
  from django.db.models.query_utils import DeferredAttribute
@@ -70,7 +70,7 @@ class StructuredJSONField(JSONField):
70
70
 
71
71
  return list_data_validator
72
72
 
73
- def __init__(self, schema: type[BaseModel], *args: Any, **kwargs: Any) -> None:
73
+ def __init__(self, schema: Type[BaseModel], *args: Any, **kwargs: Any) -> None:
74
74
  self.orig_schema = schema
75
75
  self.schema = schema
76
76
  default = kwargs.get("default", dict)
@@ -81,7 +81,7 @@ class StructuredJSONField(JSONField):
81
81
  if self.many:
82
82
  self.schema = TypeAdapter(
83
83
  Annotated[
84
- list[self.schema],
84
+ List[self.schema],
85
85
  Field(default_factory=list),
86
86
  WrapValidator(self.list_data_validator),
87
87
  ]
@@ -96,7 +96,7 @@ class StructuredJSONField(JSONField):
96
96
  return isinstance(value, self.orig_schema)
97
97
 
98
98
  def get_prep_value(
99
- self, value: Union[list[type[BaseModel]], type[BaseModel]]
99
+ self, value: Union[List[Type[BaseModel]], Type[BaseModel]]
100
100
  ) -> str:
101
101
  if isinstance(value, list) and self.many:
102
102
  return self.schema.dump_json(value, exclude_unset=True).decode()
@@ -1,6 +1,6 @@
1
1
  from collections import defaultdict
2
2
  from inspect import isclass
3
- from typing import Any, Dict, Sequence
3
+ from typing import Any, Dict, Sequence, Type, Iterable, Union
4
4
  from typing_extensions import get_args, get_origin
5
5
  from camomilla.settings import STRUCTURED_FIELD_CACHE_ENABLED
6
6
  from camomilla.structured.fields import ForeignKey, QuerySet
@@ -8,7 +8,6 @@ from camomilla.structured.models import BaseModel
8
8
  from camomilla.structured.utils import _LazyType, get_type, pointed_setter
9
9
  from django.db.models import Model as DjangoModel
10
10
  from camomilla.utils.getters import pointed_getter
11
- from typing import Iterable, Union
12
11
 
13
12
 
14
13
  # TODO:
@@ -26,7 +25,7 @@ class ValueWithCache:
26
25
  def __init__(self, cache, model, value) -> None:
27
26
  self.cache: Cache = cache
28
27
  self.value: Union[Iterable[Union[str, int]], str, int] = value
29
- self.model: type[DjangoModel] = model
28
+ self.model: Type[DjangoModel] = model
30
29
 
31
30
  def retrieve(self):
32
31
  cache = self.cache.get(self.model)
@@ -67,7 +66,7 @@ class CacheBuilder:
67
66
  return cls(related_fields=cls.inspect_related_fields(model))
68
67
 
69
68
  @classmethod
70
- def inspect_related_fields(cls, model: type[BaseModel]) -> Dict[str, RelInfo]:
69
+ def inspect_related_fields(cls, model: Type[BaseModel]) -> Dict[str, RelInfo]:
71
70
  related = {}
72
71
  for field_name, field in model.model_fields.items():
73
72
  annotation = field.annotation
@@ -84,7 +84,7 @@ class QuerySet(Generic[T]):
84
84
  model_class = get_type(source)
85
85
 
86
86
  def validate_from_pk_list(
87
- values: list[Union[int, str]]
87
+ values: List[Union[int, str]]
88
88
  ) -> django_models.QuerySet:
89
89
  preserved = django_models.Case(
90
90
  *[django_models.When(pk=pk, then=pos) for pos, pk in enumerate(values)]
@@ -103,7 +103,7 @@ class QuerySet(Generic[T]):
103
103
  pk_attname = model_class._meta.pk.attname
104
104
 
105
105
  def validate_from_dict(
106
- values: list[Dict[str, Union[str, int]]]
106
+ values: List[Dict[str, Union[str, int]]]
107
107
  ) -> django_models.QuerySet:
108
108
  return validate_from_pk_list([data[pk_attname] for data in values])
109
109
 
@@ -1,5 +1,5 @@
1
1
  from collections import defaultdict
2
- from typing import Callable, Optional, TYPE_CHECKING
2
+ from typing import Callable, Optional, TYPE_CHECKING, Type, Dict
3
3
  import inspect
4
4
  from django.http import HttpRequest
5
5
 
@@ -16,7 +16,7 @@ class PagesContextRegistry:
16
16
  self,
17
17
  func: Callable,
18
18
  template_path: Optional[str],
19
- page_model: Optional[type["AbstractPage"]],
19
+ page_model: Optional[Type["AbstractPage"]],
20
20
  ):
21
21
  assert (
22
22
  template_path is not None or page_model is not None
@@ -26,7 +26,7 @@ class PagesContextRegistry:
26
26
  if page_model is not None:
27
27
  self._model_registry[page_model].add(func)
28
28
 
29
- def get_registered_info(self) -> dict[str, dict]:
29
+ def get_registered_info(self) -> Dict[str, dict]:
30
30
  info = defaultdict(dict)
31
31
  for k, v in self._template_registry.items():
32
32
  for f in v:
@@ -43,7 +43,7 @@ class PagesContextRegistry:
43
43
  return info
44
44
 
45
45
  def get_wrapper_context_func(
46
- self, template_path: str, page_model: type["AbstractPage"]
46
+ self, template_path: str, page_model: Type["AbstractPage"]
47
47
  ) -> Callable:
48
48
  all_funcs = set()
49
49
  for cls in self._model_registry.keys():
@@ -73,7 +73,7 @@ class PagesContextRegistry:
73
73
 
74
74
  def register(
75
75
  template_path: Optional[str] = None,
76
- page_model: Optional[type["AbstractPage"]] = None,
76
+ page_model: Optional[Type["AbstractPage"]] = None,
77
77
  ):
78
78
  assert (
79
79
  template_path is not None or page_model is not None
@@ -1 +1 @@
1
- __version__ = "6.0.0-beta.11"
1
+ __version__ = "6.0.0-beta.13"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-camomilla-cms
3
- Version: 6.0.0b11
3
+ Version: 6.0.0b13
4
4
  Summary: Django powered cms
5
5
  Author-email: Lotrèk <dimmitutto@lotrek.it>
6
6
  License: MIT
@@ -1,4 +1,4 @@
1
- camomilla/__init__.py,sha256=2BNFRfFpxaxf6AQdUf-_3_5NA-FPAH6mUN8Xa9DvDzE,251
1
+ camomilla/__init__.py,sha256=90D5d1Eo-RHeFug2xM5JHCF6vTFsJbCV_XYQqUIMlpc,251
2
2
  camomilla/apps.py,sha256=eUwb9ynyiRAc5OXgt7ZsAdhsCOnPCpNdIFYMheNeN-o,532
3
3
  camomilla/authentication.py,sha256=jz6tQT4PPEu-_JLox1LZrOy7EiWBb9MWaObK63MJGus,855
4
4
  camomilla/context_processors.py,sha256=cGowjDZ-oDGYn1j2Pj5QDGCqnzXAOdOwp5dmzin_FTc,165
@@ -16,18 +16,20 @@ camomilla/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
16
16
  camomilla/contrib/modeltranslation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  camomilla/contrib/modeltranslation/hvad_migration.py,sha256=UanLVSlYYd_ykMC4STtYkkUMJqlFQQYhbWkoV47alM0,5403
18
18
  camomilla/contrib/rest_framework/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- camomilla/contrib/rest_framework/serializer.py,sha256=vOtATWxcVcn8EGzRElklmspjtalCa4nGGgeMMARjihA,5918
19
+ camomilla/contrib/rest_framework/serializer.py,sha256=G6SKes-8RkJKDupCNN0B2B1BQuYqS0y820oGYotxPcY,5924
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
23
23
  camomilla/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  camomilla/management/commands/regenerate_thumbnails.py,sha256=pKToASR8p8TJezGpFfuylsAHtriNueJ7xqJJxq55adY,496
25
+ camomilla/managers/__init__.py,sha256=Zwp28E1RKafIl0FqcUi1YNHxF19IsMIvhlhS-Njg9Mw,60
26
+ camomilla/managers/pages.py,sha256=FVXEW1G-O32kUJO4wejYi8QuDp1DIF5FOyj1rSewS0k,1380
25
27
  camomilla/models/__init__.py,sha256=y7Q34AGhQ1weJUKWb6XjiyUbwRnJeylOBGMErU0wqYg,147
26
28
  camomilla/models/article.py,sha256=LgkZgRsubtDV6NwBz8E2bIgKD6H3I-1QLAxEan5TYYs,1139
27
29
  camomilla/models/content.py,sha256=mIgtifb_WMIt58we5u6qWZemHvuDN1zZaBeCyzHL78A,956
28
30
  camomilla/models/media.py,sha256=7TD_0nhNoi8P-Gmsr0Kag4eGaxMXuTfQOFl53Mb03cQ,6854
29
- camomilla/models/menu.py,sha256=GdywN50yp7ezXzy8SF8P-W3ejey31ZPlJYp2cEM38Uk,2835
30
- camomilla/models/page.py,sha256=LGCRC-opHofAHfShhfByNcaNlQUq6f2NCZcz-XG1o7Y,14642
31
+ camomilla/models/menu.py,sha256=rCq0MfHLGM7-7fDVk--AixQZb6_C1gkWMWffKs6QnK4,2841
32
+ camomilla/models/page.py,sha256=X4Mo4cTbAYyWlpVFtjRjyvI_wE2-zcBU1MR8mm26NQI,15671
31
33
  camomilla/models/mixins/__init__.py,sha256=c2NixqvrIX4E9WGRqQbylXlqBWDXEqN9mzs_dpB0hFQ,1248
32
34
  camomilla/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
35
  camomilla/openapi/schema.py,sha256=kYNtIKnLx4SIj893umIE6u-q3HH9hYH9O4zdZCSOe7U,2100
@@ -43,15 +45,15 @@ camomilla/serializers/validators.py,sha256=QtlmGyJiKaKyMBqBZ1W2VAjCoLi1vhPUnLOo7
43
45
  camomilla/serializers/base/__init__.py,sha256=HSDBPXQ3ldX0pixDbNLna5LSUQ_TfFZ4JWKRm6OpWcU,793
44
46
  camomilla/serializers/fields/__init__.py,sha256=P3WFxrNGNBKTYqXi-CA4e5HLOYWo6Yt6izQcwyUhBPU,642
45
47
  camomilla/serializers/fields/file.py,sha256=yjKMho2ti9TIAzo6nwyLnNPJ6GVUumL2wxhegvYqI2o,800
46
- camomilla/serializers/fields/json.py,sha256=IHXqvyM1SsOKOIcRVCyPHPNaIOBYG1E9CuTcfQzR7kE,1858
48
+ camomilla/serializers/fields/json.py,sha256=KHSxklGr1dLS6yd8nkVo_S7BiJKVMJ8Iv8vXyR8aCVQ,1870
47
49
  camomilla/serializers/fields/related.py,sha256=Lofgk582KAb0EIK20jtds538O_y-yRHo644ND_VlXrM,4747
48
- camomilla/serializers/mixins/__init__.py,sha256=47CmlSOw2i2t8rZadFYn2Aa2SFbk5h0IaBmvzmGFeTQ,7367
50
+ camomilla/serializers/mixins/__init__.py,sha256=lvPCwDNZtQwdewIQUVI-D9f2UuwxjVs29TNTozcahzs,7377
49
51
  camomilla/storages/__init__.py,sha256=ytGgX59Ar8vFfYz7eV8z-j5yO_5FqxdZM25iyLnJuSA,131
50
52
  camomilla/storages/optimize.py,sha256=YKbhSbTaWNbTFIRTRWdilD3w8b_LjMLOmE6yk2lrbo4,2745
51
53
  camomilla/storages/overwrite.py,sha256=CO_zSZxr321eohYFuzPjDMK7WMFnvvwlIigIPabU_eE,343
52
- camomilla/structured/__init__.py,sha256=XHXq9oEXsgrlxzqMvN3WgXBKOD34n78RpVJn0xPnZbw,4326
53
- camomilla/structured/cache.py,sha256=LVulN5Z8v3_Cd7GSm2W_6uOZDpAg4WocWPTpoAL_82M,7857
54
- camomilla/structured/fields.py,sha256=VZi-qCZk-GEIKnkB-z5xC0a2vXa1rSaoC-rQSiDfpIo,5237
54
+ camomilla/structured/__init__.py,sha256=mX0mruLSrovzKlIk4WLBw-eFOuxbFVh9ASA5lR5OVF4,4338
55
+ camomilla/structured/cache.py,sha256=Fi6F3oQzq8XcbGglKes-U1SskFzTnvowZY82S5eeOCU,7845
56
+ camomilla/structured/fields.py,sha256=INjb6G67k4nmeGQibU0WBHUUpRJQbYmcX74sWvBLMUs,5237
55
57
  camomilla/structured/models.py,sha256=us03rOU2VtdhH4MMHIGkb11Wr6ItxPmB7ZUL1QepWmg,1790
56
58
  camomilla/structured/utils.py,sha256=nJlRFuYkBOgqxMWEpCM5qGu2m7j9TCBHB8SMmZPbCKM,3447
57
59
  camomilla/templates/admin/camomilla/page/change_form.html,sha256=ig7rRUtylDZMINBQuVPpZLmeB4sOTV_VtqnTgzAyxEo,251
@@ -63,11 +65,11 @@ camomilla/templates/defaults/parts/menu.html,sha256=KBgXv23dCWW0XM16R5fT0_g-w_qu
63
65
  camomilla/templates/defaults/widgets/media_select_multiple.html,sha256=k2XYou8KkPuFLnPMkPJAFJ-zGJj2Xvu6R3ZmiKa3g7Q,3727
64
66
  camomilla/templates_context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
67
  camomilla/templates_context/autodiscover.py,sha256=td7SCsqg3iNPnv1HDEDEpwWgWLjy5Zmc8Nbze1_J46I,1907
66
- camomilla/templates_context/rendering.py,sha256=CyMFKPo8YIJzITco748z56-zsxwBUcZ_p3a4pqRORnQ,3182
68
+ camomilla/templates_context/rendering.py,sha256=GfTR45_gC7WT7zTKPVXkBDwe22uF63A-DfZUW31woAU,3194
67
69
  camomilla/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
70
  camomilla/templatetags/camomilla_filters.py,sha256=35x0-cWrRHeLhqypSLlJzEFY_fQDcRHiwZQpFgIsspE,692
69
71
  camomilla/templatetags/menus.py,sha256=pLFeJ1UAm3flsU9TNo2iQk4otSwZuJPr86Nf408dZ-8,862
70
- camomilla/theme/__init__.py,sha256=ira55pWvXTA963-tYT1zxy1akZHXw825C7GDJWk1zec,30
72
+ camomilla/theme/__init__.py,sha256=mU1IlOIVAJC-fMxsbdHtQSVGPT8J6cMmDZXINJZJvBc,30
71
73
  camomilla/theme/admin.py,sha256=R3QAfqaF9mhzwfyb_m2_hqTQ2hBcNvQts1MWUX4dUUM,2462
72
74
  camomilla/theme/apps.py,sha256=ecqG8ntWdOighYOEHQOMVQpa5g_1WEzzpaaGjnOi9uA,1195
73
75
  camomilla/theme/static/admin/css/responsive.css,sha256=yGq6qXrr8xEVsXTnprIBgkX-sMGZrNf0Kkh-xDxf6yE,157
@@ -100,8 +102,8 @@ tests/test_api.py,sha256=DTXtvNNRwvZvxGKi6LyCzhpyU1OzPWGSbBUfRL3-Nck,2101
100
102
  tests/test_camomilla_filters.py,sha256=_W9CcwsEyewMBvnNYKk4CVqrkXxRYejle3mjiBS7hqk,1848
101
103
  tests/test_models.py,sha256=WJs8lxWZWn1l7X3a_QFVc8fF5LHTsI8bc3uhQe6-o-Q,684
102
104
  tests/test_utils.py,sha256=0tdEDBaBkyjAXpbqP0SpFcfgO56MV2TWZmk9xpjR7J0,3613
103
- django_camomilla_cms-6.0.0b11.dist-info/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
104
- django_camomilla_cms-6.0.0b11.dist-info/METADATA,sha256=qfgL0naKWllfS769fseOM4nz5Wg8QF1M7YG23yvZ9hI,2410
105
- django_camomilla_cms-6.0.0b11.dist-info/WHEEL,sha256=P2T-6epvtXQ2cBOE_U1K4_noqlJFN3tj15djMgEu4NM,110
106
- django_camomilla_cms-6.0.0b11.dist-info/top_level.txt,sha256=G9VIGBmMMqC7JEckoTgXKmC6T2BR75QRkqRnngw1_lo,16
107
- django_camomilla_cms-6.0.0b11.dist-info/RECORD,,
105
+ django_camomilla_cms-6.0.0b13.dist-info/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
106
+ django_camomilla_cms-6.0.0b13.dist-info/METADATA,sha256=axotQ6_8ytKQdCOmKjySs29ExAKuIF8KHcnTqZLoZEM,2410
107
+ django_camomilla_cms-6.0.0b13.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
108
+ django_camomilla_cms-6.0.0b13.dist-info/top_level.txt,sha256=G9VIGBmMMqC7JEckoTgXKmC6T2BR75QRkqRnngw1_lo,16
109
+ django_camomilla_cms-6.0.0b13.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.3)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any