Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

DISCLAIMER: This RFC was created by @macolo

Intro

Why these policies?

  • To have clear guidelines on how to integrate with other developer's packages in the django CMS ecosystem
  • To enable package developers to contribute to django CMS in a more interoperable way
  • To help project developers to seamlessly blend custom functionality with django CMS ecosystem packages.
  • To have a consistent plugin endorsement strategy for the django CMS ecosystem. Plugins considered to be part of the django CMS ecosystem are listed here: https://docs.google.com/spreadsheets/d/1kANl66x5CLoL3ZcL613Qz1sClfnDvh9jk8csrh9cSQM

Who is this for?

  • All developers that contribute functionality to django CMS in the form of third-party, public github repositories and/or pypi packages

Proposed Principles

  • django CMS ecosystem should be a flexible framework to add CMS functionality to any django project.
  • django CMS packages should not depend on each other. They should offer dependencies to peer packages as optional Pypi dependencies. Examples:
    • djangocms-bootstrap4 should not depend on djangocms-picture, django-filer, djangocms-attributes-field, djangocms-text-ckeditor, djangocms-icon and djangocms-link
    • djangocms-bootstrap4[djangocms-picture] depends on djangocms-picture
    • djangocms-bootstrap4[djangocms-attributes-field] depends on djangocms-attributes-field
    • djangocms-bootstrap4[djangocms-text-ckeditor] depends on djangocms-ckeditor
    • djangocms-bootstrap4[djangocms-icon] depends on djangocms-icon
    • djangocms-bootstrap4[djangocms-link] depends on djangocms-link
    • djangocms-page-meta should not depend on django-filer
    • djangocms-page-meta[django-filer] depends on django-filer
    • djangocms-text-ckeditor should not depend on django-filer
    • djangocms-text-ckeditor[django-filer] depends on django-filer
    • djangocms-link-all should not depend on django-filer
    • djangocms-link-all[django-filer] depends on django-filer
    • django-frontify[djangocms-text-ckeditor] depends on djangocms-ckeditor
  • If django CMS packages contain django apps their application code should refer to swappable models. Examples:
    • djangocms-page-meta's TitleMeta and PageMeta models should be swappable.

Problem Statement /Painpoints

It's cumbersome to work around hard-coded package functionality and dependencies

  • Example 1 (CMS plugin):
    • A project developer would like to use Frontify (django-frontify) instead of the default django-filer for asset management, allowing editors to store and manages images and videos on frontify and reference them in all image fields across the project's plugin forms and other django admin forms.
    • The project developer would also like to use the djangocms-bootstrap4 pypi package.
    • However djangocms-bootstrap4 ships with Bootstrap4Picture plugin which includes a hard-coded FilerImageField which cannot be replaced.
  • Example 2 (django app):
    • A project developer would like to use Frontify instead of the default django-filer for asset management (etc.)
    • The project developer would also like to use djangocms-page-meta in his project.
    • However djangocms-page-meta ships with a hard-coded FilerImageField which cannot be replaced.

Solution Approaches

Unregister Plugins and Application Toolbars

  • This is the cheapest but least perfect solution if you want to override model fields in a third-party package.
  • django CMS allows to unregister plugins in an arbitrary admin.py file (preferrably just before registering your replacing ModelAdmin class)
  • django CMS also allows to unregister django CMS application toolbars in an arbitrary cms_menus.py file
  • Like this default plugins can be hidden from editors and the project developer can then replace them with their own custom plugins own.

A note about overriding django application (non-plugin) models:

  • django admin allows to unregister ModelAdmin classes (example). A project developer can unregister the package's ModelAdmin, inherit from it, change it and then register their own ModelAdmin class.
  • The packages django templates can be overridden in the project's source code
  • Limitation: The application logic (in views.py) cannot be overridden, so in most cases application packages source code will have to be copied anyway.

Swappable Models in pypi packages

  • Swappable models allow a project developer to change a database model even if it is defined in a third-party package.
  • Swappable Models is a django best practise approach.
  • For example, django "highly recommends" to swap the default User model at the very start of a project to maximise flexibility throughout the project's life time.
  • abstract models have the advantage that they are not active in a project when installing the containing package via pypi.
  • A default plugin model can be provided by the package as abstract base class. The project developer can inherit from the abstract base model.
    • overriding fields is possible by redefining them in their child model
    • removing fields is possible (field_name = None).
    • If the project does not require any changes to the base model, project developers can simply inherit from the abstract base model and register that model in the project's settings.py. That's just 4 additional lines of code.

Use pypi optional dependencies

  • For example djangocms-bootstrap4[filer] will install djangocms-bootstrap4 with plugins that depend on filer
  • ...while djangocms-bootstrap4 will not include the Bootstrap4PicturePlugin (which relies on filer)
  • this would allow project developers to use a base djangocms-boostrap4 package and add their own implementations for a picture plugin that might rely on a completely different asset management system (like google drive).

Split functionality into completely separate repositories

  • this is a brute-force approach where the plugins that depend on integrations with other packages are ripped out of the original plugin and published as separate pypi packages. This option is inferior to using pypi optional dependencies in most cases.
You must be logged in to vote

Replies: 4 comments · 3 replies

Comment options

In example 1 (CMS plugin) you propose to add a layer to wrap the hard-coded filer. FilerImageFieldinto a field suitable for both, django-filer and django-frontify to abstract the assets management library away.

In my opinion, even though this is well intended, it will result in wrappers which only offer the smallest common denominator. It might be that those libraries implement different fields and/or methods which then are available to neither of the plugins.

This in my opinion will make development harder, rather than simpler.

And btw. if you look at djangocms-cascade, there I make intensive use of internal dependencies. For instance, its own TextLinkPlugin depends on an abstract LinkPluginMixin. The latter is used by its PicturePlugin, its ButtonPlugin, its IconPlugin and all other plugins which require linking functionality. There I intentionally reuse that functions in order to stay DRY, rather than having to reimplement the linking functionality for all of them again and again.

Just my two cents...

You must be logged in to vote
2 replies
@NicolaiRidani
Comment options

NicolaiRidani Jul 26, 2021
Maintainer Author Sponsor

@macolo FYI

@macolo
Comment options

macolo Jul 30, 2021
Maintainer Sponsor

hi @jrief thanks for your comment, it pointed me at a mistake in example 1. I updated the problem statement in example 1 and now it should be ok and a lot simpler as well.

Comment options

one comment concerning Unregister Plugins and Application Toolbars: Plugins can easily be hidden when using the CMS_PLACEHOLDERS setting. Also, I'm often having a "configure" app, last in INSTALLED_APPS, that has a cms_plugins.pywhich unregisters plugin(s), redefines some things for example in the form or whatever, and re-registers the same plugin.

I really like the "swappable model" approach as kind of a default one, as for now, I dont use any third party plugins...right because of that. Would the developer need to configure MIGRATION_MODULES, when swapping a model? Or even in any case, as the app/plugin would not provide any migrations at all?

You must be logged in to vote
1 reply
@NicolaiRidani
Comment options

NicolaiRidani Oct 8, 2021
Maintainer Author Sponsor

FYI @macolo

Comment options

NicolaiRidani
Oct 8, 2021
Maintainer Author Sponsor

This policy was unanimously approved by the Tech Committee (see meeting logs)

You must be logged in to vote
0 replies
Comment options

fsbraun
Aug 31, 2022
Maintainer Sponsor

Just introduced this to djangocms-snippet (djangocms-static-ace), partially to djangocms-frontend (djangocms-static-ace, djangocms-icon) 😎 Still looking for help on how to make the Django-filer dependency swappable in djangocms-frontend ...

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
5 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.