dynamicweb/cms/models/fields.py

102 lines
3.6 KiB
Python

from itertools import chain
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from cms.forms.fields import PageSelectFormField
from cms.models.placeholdermodel import Placeholder
class PageField(models.ForeignKey):
"""
This is a foreign key field to the :class:`cms.models.pagemodel.Page` model
that defaults to the :class:`~cms.forms.fields.PageSelectFormField` form
field when rendered in forms. It has the same API as the
:class:`django:django.db.models.ForeignKey` but does not require
the ``othermodel`` argument.
"""
default_form_class = PageSelectFormField
def __init__(self, **kwargs):
# We hard-code the `to` argument for ForeignKey.__init__
# since a PageField can only be a ForeignKey to a Page
kwargs['to'] = 'cms.Page'
kwargs['on_delete'] = models.CASCADE
super().__init__(**kwargs)
def formfield(self, **kwargs):
defaults = {
'form_class': self.default_form_class,
}
defaults.update(kwargs)
return super().formfield(**defaults)
class PlaceholderField(models.ForeignKey):
"""
.. warning::
This field is for django CMS versions below 4 only. It may only be used inside migrations.
The ``PlaceholderField`` has been replaced by the :class:`~cms.models.fields.PlaceholderRelationField`,
the built-in migrations will automatically take care of the replacement.
See documentation of :class:`~cms.models.fields.PlaceholderRelationField` for how to replace the code.
"""
system_check_removed_details = {
"msg": (
"PlaceholderField is for django CMS versions below 4 only. It may only be used inside migrations."
),
"hint": "Use PlaceholderRelationField instead.",
"id": "cms.E001",
}
def __init__(self, slotname, *args, **kwargs):
kwargs.update({'null': True}) # always allow Null
kwargs.update({'editable': False}) # never allow edits in admin
# We hard-code the `to` argument for ForeignKey.__init__
# since a PlaceholderField can only be a ForeignKey to a Placeholder
self.slotname = slotname
kwargs['to'] = 'cms.Placeholder'
kwargs['on_delete'] = models.CASCADE
super().__init__(**kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs['slotname'] = self.slotname
return name, path, args, kwargs
class PlaceholderRelationField(GenericRelation):
""":class:`~django.contrib.contenttypes.fields.GenericForeignKey` to placeholders.
If you create a model which contains placeholders you first create the ``PlaceHolderRelationField``::
from cms.utils.placeholder import get_placeholder_from_slot
class Post(models.Model):
...
placeholders = PlaceholderRelationField() # Generic relation
@cached_property
def content(self):
return get_placeholder_from_slot(self.placeholders, "content") # A specific placeholder
"""
default_checks = []
def __init__(self, checks=None, **kwargs):
self._checks = checks or ()
kwargs.pop('object_id_field', None)
kwargs.pop('content_type_field', None)
super().__init__(
Placeholder,
object_id_field='object_id',
content_type_field='content_type',
**kwargs
)
@property
def checks(self):
return chain(self.default_checks, self._checks)
def run_checks(self, placeholder, user):
return all(check_(placeholder, user) for check_ in self.checks)