Multisite Custom Site Model

Since feincms3-sites 0.13.1 you can use a custom site model instead of the default provided feincms3_sites.Site.

Configuration

First, make sure that you adjust your Django settings accordingly:

# FEINCMS3_SITES_SITE_MODEL = "feincms3_sites.Site"
FEINCMS3_SITES_SITE_MODEL = "myapp.Site"

From now on, Django will use your custom site model.

Implementing a Custom Site Model

Next, you have to implement your custom site model, by adding the following to your models, e.g.:

from feincms3_sites.models import AbstractSite
from feincms3_meta.models import MetaMixin

class CustomSite(AbstractSite, MetaMixin):
    name = models.CharField(max_length=100, blank=False, null=False)

    def __str__(self):
        return "{} ({})".format(self.name, self.host)

The above will add the additional name field to the site that is also used for display in dropdowns and lists in the site admin, e.g. MySite (localhost:8000).

It will also inherit meta fields declared by the MetaMixin that can be used for providing default meta information to the pages associated with that site. (you will have to install feincms3-meta and enable the app in your Django settings to use it.)

Please note that the metadata from the site will not be added automatically, you will have to do this in your view, e.g.

from django.shortcuts import get_object_or_404, render, redirect

from feincms3_meta.utils import meta_tags

from .models import Page
from .renderer import renderer


def page_detail(request, path=None):
    """
    The view expects uri paths to be formed as such

    [[/<language-code>][/<path>]]

    in case of an empty uri path the view will redirect the user to

    /<site.default_language/

    expecting a root page to exist that has the appropriate path

    otherwise, the provided uri path will be used and the system will
    try to retrieve a probably existing page via the ORM.
    """
    actual_site = request.site
    if not path:
        # Make sure that the user is redirected to the correct url.
        # We expect a root page with custom path /<default_language>/ to
        # exist here.
        redirect_path = "/{}/".format(actual_site.default_language)
        return redirect(redirect_path)

    actual_path = "/{}/".format(path)
    page = get_object_or_404(
        Page.objects.active(),
        path=actual_path
    )
    page.activate_language(request)
    ancestors = page.ancestors().reverse()
    meta_data_providers = [page] + list(ancestors) + [page.site]
    return render(
        request,
        page.type.template_name,
        {
            "page": page,
            "page_regions": renderer.regions_from_item(
                page,
                inherit_from=ancestors,
                timeout=60,
            ),
            "meta_tags": meta_tags(
                meta_data_providers,
                request=request,
                # The default site model doesn't have a name attribute, see
                # the custom site model above.
                site_name=page.site.name,
            )
        },
    )

Make sure that your custom site model gets registered with the Django ORM before your page model gets registered, otherwise there will be an exception telling you that the site model configured in FEINCMS3_SITES_SITE_MODEL does not exist.

Remember to update your migrations as well:

./manage.py makemigrations
./manage.py migrate

Implementing a Custom Site Model Admin

from django.contrib import admin
from django.utils.translation import gettext_lazy as _

from feincms3_sites.admin import DefaultLanguageListFilter
from feincms3_sites.admin import SiteAdmin
from feincms3_meta.models import MetaMixin

from .models import Site


@admin.register(Site)
class CustomSiteAdmin(SiteAdmin):
    list_display = [
        "name", "host", "default_language", "is_active", "is_default"
    ]

    list_filter = [
        "is_active", "host", "name", DefaultLanguageListFilter
    ]

    fieldsets = [
        (None, {
            "fields": [
                "name",
                "host",
                "default_language",
                "is_active",
                "is_default",
            ],
        }),
        (_("Advanced Settings"), {
            "fields": [
                "is_managed_re",
                "host_re",
            ],
            "classes": [
                "tabbed"
            ],
        }),
        MetaMixin.admin_fieldset()
    ]

By default, the admin edit/create page will display itself as a flat admin page, i.e. there will not be any tabs.

In comes the django-content-editor and the scripts and other media it provides.

So to have tabs on your custom site model’s admin page, add the following to the SiteAdmin:

...

class CustomSiteAdmin(SiteAdmin):

    ...

    class Media:
        css = {
            "all": [
                "content_editor/material-icons.css",
                "content_editor/content_editor.css",
            ]
        }
        js = [
            "admin/js/jquery.init.js",
            "content_editor/tabbed_fieldsets.js",
        ]