django-lite-cms-core

Warning

The docs is work in progress, so it is not completed by now and will be subject to change.

django-lite-cms is a lightweight and modular CMS addon for Django. This package contains the core classes that are needed to get basic CMS properties.

Installation

django-lite-cms-core can be found on pypi. Run:

pip install django-lite-cms-core

to install the package on your machine or in your virtual environment.

Dependencies

If you install django-lite-cms-core the following modules will be installed, because django-lite-cms-core depends on them:

  • django-bootstrap5

    Currently the templates used in django-lite-cms-core use django-bootstrap5. You can avoid this dependency by overriding the templates to use none or another css framework.

  • django-admin-sortable2

    The AdminOrderMixin is based on django-admin-sortable2. If you don’t use the ordering, you can remove the dependency.

  • django-tinymce

    django-tinymce provides the HTML field for the ContentFieldMixin.

  • django-filebrowser-no-grappelli

    The django-filebrowser-no-grappelli library provides the media management for the tinymce HTML field.

  • Pillow

    Pillow is a dependency of django-filebrowser-no-grappelli

Settings

django-lite-cms-core doesn’t need any specific settings. But most of the dependencies need some settings. Please refer to the specific modules documentation to get the settings docs:

Note

django-filebrowser-no-grappelli doesn’t provide any explicit documentation but refers to the django-filebrowser (with grappelli) version.

Getting Started

To integrate django-lite-cms-core with your site, follow the steps as listed:

  1. Add this application in the INSTALLED_APPS portion of your settings file. Your settings file will look something like:

    INSTALLED_APPS = (
        # ...
        'lite_cms_core',
    )
    
  2. Add the lite_cms_core urls to the end of your root urlconf. Your urlconf will look something like:

    urlpatterns = [
        # ...
        path('lite_cms_core/', include('lite_cms_core.urls')),
    ]
    

Note

You need to include the url patterns ony if you want to use the search functionality.

To make use of the classes create a model that inhertits from them like this:

class BlogPost(ContentFieldMixin, TimeStampedMixin, SluggedMixin, BaseEntity):
    """
    A blog post.
    """

    class Meta:
        verbose_name = _("Blog post")
        verbose_name_plural = _("Blog posts")
        ordering = ("-created",)

    def __str__(self):
        return self.title

    author = models.ForeignKey(
        User, verbose_name=_('Author'), on_delete=models.PROTECT
    )
    categories = models.ManyToManyField(
        "BlogCategory", verbose_name=_("Categories"),
        blank=True, related_name="blogposts"
    )

    # Specify the fields for searching
    search_fields = {"title", "content"}

    def get_absolute_url(self):
        return reverse('blog:blogpost-detail', args=[str(self.slug)])

Model Classes

Django Lite CMS base classes.

class lite_cms_core.models.AdminOrderMixin(*args, **kwargs)

Let the user order the model instances in admin.

The mixin adds a sort_order positive integer field to the class, which is a prerequisite for the django-admin-sortable2 module.

Since inner classes are not inherited, it would make no sense to set the ordering here. So it’s up to you to set the ordering to ordering = ['sort_order'].

In the admin please inherit from SortableAdminMixin as described in the docs of django-admin-sortable2.

class lite_cms_core.models.BaseEntity(*args, **kwargs)

Abstract base model for basic cms funcionality.

expiry_date

Time and date when the entity is expired, so will not be seen by users anymore.

get_absolute_url()

Get the absolute url for this object.

Raise an error if called on a subclass without get_absolute_url defined, to ensure all search results contains a URL.

get_next_by_publish_date(**kwargs)

Retrieves next object by publish date.

get_previous_by_publish_date(**kwargs)

Retrieves previous object by publish date.

publish_date

Time and date when the entity is or will be published.

property published

Get only published instances.

For non-staff users, return True when status is published and the publish and expiry dates fall before and after the current date when specified.

save(*args, **kwargs)

Save instance of base class.

If no publish_date is provided set it to now.

status

The status of the entity, one of CONTENT_STATUS_DRAFT or CONTENT_STATUS_PUBLISHED

title

Title of the entity, string with a maxlen of 200.

class lite_cms_core.models.ContentFieldMixin(*args, **kwargs)

Get a HTML edit field in model.

class lite_cms_core.models.PreventUnpublishedAccessDetailView(**kwargs)

Prenvet non staff usere form accessing draft items in DetailView.

In default an admin user will be shown model instances in both status, draft and published. Non staff users will not be shown any draft items in the admin ui or in any lists that use the .published method.

The normal DetailView will not refer to the published method but more to the get_absolute_url method. If you want to hide the draft items from non-staff users, you can use this subclass of the Django DetailView.

dispatch(request, *args, **kwargs)

Show HTTP 404 for not published items.

class lite_cms_core.models.SluggedMixin(*args, **kwargs)

Abstract model that handles auto-generating slugs.

In default the slug is generated from the title attribute. You can specify a different attribute by overriding the get_slug() method. if you want to get the slug from a name attribute, add this to your class:

def get_slug(self, attr=None):
    return super().get_slug(attr="name")

If any instance has the same title as another instance, a unique slug is automatically generated by adding a dash and a number.

Provides a “view on site” link for the admin site.

generate_unique_slug()

Create a unique slug for colliding sources.

Create a unique slug by passing the result of get_slug() to utils.urls.unique_slug, which appends an index if necessary.

get_slug(attr=None)

Get a unique slug.

Allows subclasses to implement their own slug creation logic. In default a model ‘title’ field is required

save(*args, **kwargs)

If no slug is provided, generates one before saving.

class lite_cms_core.models.TimeStampedMixin(*args, **kwargs)

Provides timestamps for created and modified fields.

Both fields are read-only.

changed

Time and date of the latest change of the instance.

created

Time and date when the instance was created.

lite_cms_core.models.base_concrete_model(abstract, model)

Get super-most concrete class.

Used in methods of abstract models to find the super-most concrete (non abstract) model in the inheritance chain that inherits from the given abstract model. This is so the methods in the abstract model can query data consistently across the correct concrete model.

Consider the following:

class Abstract(models.Model)

    class Meta:
        abstract = True

    def concrete(self):
        return base_concrete_model(Abstract, self)

class Super(Abstract):
    pass

class Sub(Super):
    pass

sub = Sub.objects.create()
sub.concrete() # returns Super
lite_cms_core.models.unique_slug(queryset, slug_field, slug)

Calculate a unique slug from string field.

Ensures a slug is unique for the given queryset, appending an integer to its end until the slug is unique.

lite_cms_core.models.wrapped_manager(klass)

Combine Manager with MultilungualManager.

Model Managers

Django Lite CMS Managers.

class lite_cms_core.managers.BaseEntityManager(*args, **kwargs)

Manually combines PublishedManager and SearchableManager for the BaseEntity model.

class lite_cms_core.managers.PublishedManager(*args, **kwargs)

For non-staff users, return items with a published status.

get_by_natural_key(slug)

Return item by natural key.

published(for_user=None)

Return a QuerySet of published items.

An item is published if it has the status CONTENT_STATUS_PUBLISHED and the pusblish_date is lower or equal to now and the expiry_date is grater or equal to now. If the publish_date or the expiry_date is None, they will be ignored.

Not published items will only be returned for staff users.

class lite_cms_core.managers.SearchableManager(*args, **kwargs)

Manager providing a chainable queryset.

Adapted from http://www.djangosnippets.org/snippets/562/ search method supports spanning across models that subclass the model being used to search.

contribute_to_class(model, name)

Reinstate class.

Newer versions of Django explicitly prevent managers being accessed from abstract classes, which is behaviour the search API has always relied on. Here we reinstate it.

get_queryset()

Get searchable queryset.

get_search_fields()

Returns the search field names mapped to weights as a dict.

Used in get_queryset below to tell SearchableQuerySet which search fields to use.

Search fields can be populated via SearchableManager.__init__, which then get stored in SearchableManager._search_fields, which serves as an approach for defining an explicit set of fields to be used.

Alternatively and more commonly, search_fields can be defined on models themselves. In this case, we look at the model and all its base classes, and build up the search fields from all of those, so the search fields are implicitly built up from the inheritence chain.

Finally if no search fields have been defined at all, we fall back to any fields that are CharField or TextField instances.

search(*args, **kwargs)

Proxy to queryset’s search method for the manager’s model.

Also for any models that subclass from this manager’s model if the model is abstract.

class lite_cms_core.managers.SearchableQuerySet(*args, **kwargs)

QuerySet providing main search functionality for SearchableManager.

annotate_scores()

Annotate SearchableQuerySet with scores.

If search has occurred and no ordering has occurred, decorate each result with the number of search terms so that it can be sorted by the number of occurrence of terms.

In the case of search fields that span model relationships, we cannot accurately match occurrences without some very complicated traversal code, which we won’t attempt. So in this case, namely when there are no matches for a result (count=0), and search fields contain relationships (double underscores), we assume one match for one of the fields, and use the average weight of all search fields with relationships.

order_by(*field_names)

Mark the filter as being ordered if search has occurred.

search(query, search_fields=None)

Do the search on SearchableQuerySet.

Build a queryset matching words in the given search query, treating quoted terms as exact phrases and taking into account + and - symbols as modifiers controlling which terms to require and exclude.

lite_cms_core.managers.search_fields_to_dict(fields)

Convert search fields to a dictionary.

In SearchableQuerySet and SearchableManager, search fields can either be a sequence, or a dict of fields mapped to weights. This function converts sequences to a dict mapped to even weights, so that we’re consistently dealing with a dict of fields mapped to weights, eg: (“title”, “content”) -> {“title”: 1, “content”: 1}

Views

Django Lite CMS Views.

lite_cms_core.views.ext_search_form(request)

Extended search form.

The extended search form lets users select a model to search on.

lite_cms_core.views.search(request, template='lite_cms_core/search_results.html', extra_context=None)

Display search results.

Takes an optional “contenttype” GET parameter in the form “app-name.ModelName” to limit search results to a single model.

Template Tags

Django Lite CMS base template tags.

lite_cms_core.templatetags.base_tags.edit_toolbar(model_instance=None, permission=False)

Shows the editable toolbar and adds an admin edit link if model instance is not None.

lite_cms_core.templatetags.base_tags.get_search_type(instance)

Get the content type for a model instance.

lite_cms_core.templatetags.base_tags.search_form(context, search_model_names=None)

Includes the search form with a list of models to use as choices for filtering the search by.

Models should be a string with models in the format app_label.model_name separated by spaces. The string all can also be used, in which case the models defined by the SEARCH_MODEL_CHOICES setting will be used.

Indices and tables