8000 Add/grouper admin sections by fsbraun · Pull Request #23 · django-cms/docs · GitHub
[go: up one dir, main page]

Skip to content

Add/grouper admin sections #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
173 changes: 173 additions & 0 deletions docs/how_to/16-grouper-admin.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
.. versionadded:: 4.1

.. _grouper_admin:

###############################################
How to crate an admin class for a grouper model
###############################################

***********************
What is a grouper model
***********************

django CMS uses the grouper content model structure for pages:

* The :class:`~cms.models.pagemodel.Page` is the grouper model and defines a unit (page) which can have more than one content object (page titles in different languages, for example).

* The :class:`~cms.models.contentmodels.PageContent` is the corresponding content model which contains page content that can be different for its grouping field ``language``. It also includes the placeholders for the frontend editor.

This mechanism ensures that content that is common for all pages of a languages, such as position in the page tree, or rights, are collected at the grouper model while all language-specific content is collected in the content model.

.. note::

Also this data structure is relevant for django CMS Versioning since it versions the content objects and not the grouper objects.

To this end, if you want to create models that should be versionable like the :class:`~cms.models.contentmodels.PageContent` of a :class:`~cms.models.pagemodel.Page` objects you need to define a grouper and a content model.

**Extra grouping fields** define fields of the content model by which they are grouped: :class:`~cms.models.contentmodels.PageContent` uses ``language`` as an extra grouping field. This means that one :class:`~cms.models.pagemodel.Page` object can have multiple :class:`~cms.models.contentmodels.PageContent` objets assign to which differ in their language.

If not extra grouping fields are given each grouper object can have at most one content object assigmed to it.

The language field is a typical (but not necessary) extra grouping field.

*****************************
Administrating grouper models
*****************************

To simplify creation of grouper content models, django CMS provides support for both the model admin class of the grouper model and the change and add forms of the content model.

In this scenario you will register a model admin for the grouper model and it will provide the user with the ability to view, change and add content objects, too. You will not necessarily need to add a model admin class for the content model at all (with the possible exception of a redirecting stub to allow third party apps to reverse admin views for the content model, too, see below).

To create a model admin class for a grouper model put the following code in your `admin.py`:

.. code-block:: python

class MyGrouperAdmin(GrouperModelAdmin):
# Declare content model
content_model = MyContent
# Add language tabs to change and add views
extra_grouping_fields = ("language",)
# Add grouper and content fields to change list view
# Add preview and settings action to change list view
list_display = ("field_in_grouper_model", "content__field_in_content_model", "admin_list_actions")


The property :attr:`~cms.admin.utils.GrouperModelAdmin.content_model` defines which model is used as the content model. If you do not specify a :attr:`~cms.admin.utils.GrouperModelAdmin.content_model`, django CMS will look for a model named like the grouper model but with "Content" appended. The default content model for ``Post`` would be ``PostContent``.

The content model needs to have a foreign key pointing to the grouper model. The first foreign key found is assumed to be the field by which the content objects are assigned to their grouper objects. If you have multiple foreign keys to the grouper model, please specify :attr:`~cms.admin.utils.GrouperModelAdmin.content_related_field`.


For this example there is only ``language`` as extra grouping field declared. You only have to proviude tuple of :attr:`~cms.admin.utils.GrouperModelAdmin.extra_grouping_fields` if you have any.

.. note::

All fields serving as extra grouping fields must be part of the admin’s fieldsets setting for :class:`~cms.admin.utils.GrouperModelAdmin` to work properly. In the change form the fields will be invisible.

Change list view
****************

For the list display :class:`~cms.admin.utils.GrouperModelAdmin` provides additional fields from the content model: ``content__{content_model_field_name}``. Those fields can be used in list_display just as grouper model fields and will automatically show the content of the currently selected grouping fields.

Finally, :class:`~cms.admin.utils.GrouperModelAdmin` provides two action but 10000 tons for each entry in the change list view:

* to preview the content model in the frontend editor
* to change the settings (i.e., go to the change view of the grouper object)

These are for convenience and appear as soon as ``admin_list_actions`` is added to the ``list_display`` attribute.

Example
********************

This is an example (taken from django CMS alias) on how a grouper admin might look like:

.. code-block:: python

@admin.register(Alias)
class AliasAdmin(GrouperModelAdmin):
list_display = ['content__name', 'category', 'admin_list_actions']
list_display_links = None # With action buttons a link is not needed
list_filter = (SiteFilter, CategoryFilter,) # Custom filters
fields = ('content__name', 'category', 'site', 'content__language') # feeds into fieldsets
readonly_fields = ('static_code', )
form = AliasGrouperAdminForm # Custom admin form
extra_grouping_fields = ("language",) # Language as grouping field
EMPTY_CONTENT_VALUE = mark_safe(_("<i>Missing language</i>")) # Label for missing content objects


**********************************************
Other extra grouping fields (besides language)
**********************************************

The standard templates of django CMS will work with ``language`` as an extra grouping field out of the box:

* It creates a dropdown to switch languages for the admin's change list view.
* It creates tabs to switch languages for the admin's change and add views.

To use other grouping fields you will have to do two things:

1. You will need to **supply templates** for the change list view and the change and add views that render corresponding dropdowns or other ways of selecting which content is currently being viewed.

2. You will need to **provide context** for the templates to render the valid choices.

Providing your own templates
****************************

To show a selector for your additional grouping field you need to overwrite both the :attr:`~django.contrib.admin.ModelAdmin.change_list_template` and :attr:`~django.contrib.admin.ModelAdmin.change_form_template`. Your templates can extend the default templates. Let's say you have "region" as an additional grouping field. For the **change list template** this might look like this::

{% extends "admin/cms/grouper/change_list.html" %}
{% block language_tabs %}
{# Here goes the region mark-up #}
{% if region_dropdown %}
<div class="region-selector">
...
</div>
{% endif %}
{{ block.super }}
{% endblock %}


For the **change form template** this might look like this::

{% extends "admin/cms/grouper/change_form.html" %}
{% block search %}
{# Here goes the region mark-up #}
{% if "region" in cl.model_admin.extra_grouping_fields %}
<div class="region-selector">
...
</div>
{% endif %}
{{ block.super }}
{% endblock %}


Providing the required context
******************************

To provide the required context for your additional grouping model, you will have to implement two methods in your grouper model admin.

.. code-block:: python

class MyGrouperModelAdmin(GrouperModelAdmin):
model = MyModel
extra_grouping_fields = ("region", )

...

def changelist_view(request, extra_context=None):
"""Extra context for changelist_view"""
my_context = {...} # Add context on region grouper
return super().changelist_view(request, extra_context = {
**(extra_context or {}),
**my_context
})

def get_extra_context(self, request, obj_id = None):
"""Extra context for add_view and change_view"""
my_context = {...} # Add context on region grouper
return {
**super().get_extra_context(request, obj_id),
**my_context,
}


Consider that the context will require a set of values your additional grouping field can take. In the region example this might be ``all_regions = {"americas": _("Americas"), "europe": _("Europe"), ...}``.
File renamed without changes.
File renamed without changes.
27 changes: 14 additions & 13 deletions docs/how_to/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ Using core functionality
.. toctree::
:maxdepth: 1

Use placeholders outside the CMS <02-placeholders>
Serve multiple languages <03-languages>
Serve multiple sites <04-multi-site>
Work with templates <05-templates>
Manage caching <06-caching>
Enable frontend editing for Page and Django models <07-frontend_models>
Create sitemaps <08-sitemaps>
Manage Page Types <09-page_types>
Use placeholders outside the CMS <01-placeholders>
Serve multiple languages <02-languages>
Serve multiple sites <03-multi-site>
Work with templates <04-templates>
Manage caching <05-caching>
Enable frontend editing for Page and Django models <06-frontend_models>
Create sitemaps <07-sitemaps>
Manage Page Types <08-page_types>


**************************
Expand All @@ -32,15 +32,16 @@ Creating new functionality
.. toctree::
:maxdepth: 1

Create plugins <10-custom_plugins>
Upgrading plugins for django CMS 4+ <10a-upgrade_plugins>
Create plugins <09-custom_plugins>
Upgrading plugins for django CMS 4+ <10-upgrade_plugins>
Create apphooks <11-apphooks>
Manage complex apphook configuration <12-namespaced_apphooks>
Extend the Toolbar <13-toolbar>
Customise the CMS menus <14-menus>
Create content creation wizards <15-wizards>
Extend Page & Title models <16-extending_page_contents>
Test your extensions <17-testing>
Create admin for grouper models <16-grouper-admin>
Extend Page & Title models <18-extending_page_contents>
Test your extensions <19-testing>

*********************
Sharing functionality
Expand All @@ -49,4 +50,4 @@ Sharing functionality
.. toctree::
:maxdepth: 1

CMS application configuration <18-cms-config.rst>
CMS application configuration <20-cms-config.rst>
1 change: 1 addition & 0 deletions docs/introduction/02-templates_placeholders.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ You'll find the site's templates in ``django-cms-quickstart/backend/templates``.
By default, pages in your site will use the ``fullwidth.html`` template, the first one listed in
the project's ``settings.py`` ``CMS_TEMPLATES`` tuple:


.. code-block:: python
:emphasize-lines: 6

Expand Down
21 changes: 21 additions & 0 deletions docs/reference/utility-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ Utility functions
Utility functions provide functionality that is regularly used within the django CMS core and are also available to
third party packages.

*************
Model admin
*************

.. module:: cms.admin.utils

Action buttons
**************

.. autoclass:: ChangeListActionsMixin
:members:
:show-inheritance:

Grouper admin
*************

.. autoclass:: GrouperModelAdmin
:members:
:show-inheritance:


************
Placeholders
************
Expand Down
0