[Fixed]-How to add some extra fields to the page in django-cms? (in django admin panel)

25đź‘Ť

âś…

Create a new app (called extended_cms or something) and in models.py create the following:

from django.db import models
from django.utils.translation import ugettext_lazy as _
from cms.models.pagemodel import Page

class ExtendedPage(models.Model):   
    page = models.ForeignKey(Page, unique=True, verbose_name=_("Page"), editable=False, related_name='extended_fields')
    my_extra_field = models.CharField(...)

then create an admin.py:

from models import ExtendedPage
from cms.admin.pageadmin import PageAdmin
from cms.models.pagemodel import Page
from django.contrib import admin

class ExtendedPageAdmin(admin.StackedInline):
    model = ExtendedPage
    can_delete = False

PageAdmin.inlines.append(ExtendedPageAdmin)
try:
    admin.site.unregister(Page)
except:
    pass
admin.site.register(Page, PageAdmin)

which will add your extended model to as an inline to any page you create. The easiest way to access the extended model setttings, is to create a context processor:

from django.core.cache import cache
from django.contrib.sites.models import Site

from models import ExtendedPage

def extended_page_options(request):
    cls = ExtendedPage
    extended_page_options = None    
    try:
        extended_page_options = request.current_page.extended_fields.all()[0]
    except:
        pass
    return {
        'extended_page_options' : extended_page_options,
    }

and now you have access to your extra options for the current page using {{ extended_page_options.my_extra_field }} in your templates

Essentially what you are doing is creating a separate model with extra settings that is used as an inline for every CMS Page. I got this from a blog post previously so if I can find that I’ll post it.

EDIT

Here is the blog post: http://ilian.i-n-i.org/extending-django-cms-page-model/

7đź‘Ť

There is an official way to extend the page & title models, I highly recommend this official documentation:

I also highly recommend using a placeholder if you can, since writing this answer, I now prefer creating a placeholder for the use case of cover images. (You can even get just the image URL in your template if you want to).

Summary of the link:

  1. Create a subclass of PageExtension in your models.py file and register it:

    class IconExtension(PageExtension):
        image = models.ImageField(upload_to='icons')
    
    extension_pool.register(IconExtension)
    
  2. Create also a subclass of PageExtensionAdmin in your admin.py file and register it:

    class IconExtensionAdmin(PageExtensionAdmin):
        pass
    
    admin.site.register(IconExtension, IconExtensionAdmin)
    
  3. Finally, to make it accessible from the toolbar, create a subclass of ExtensionToolbar in cms_toolbars.py and register it:

    @toolbar_pool.register
    class IconExtensionToolbar(ExtensionToolbar):
        model = IconExtension
    
        def populate(self):
            current_page_menu = self._setup_extension_toolbar()
            if current_page_menu:
                page_extension, url = self.get_page_extension_admin()
                if url:
                    current_page_menu.add_modal_item(_('Page Icon'), url=url,
                        disabled=not self.toolbar.edit_mode)
    

The official documentation goes into more detail and explanation.

There is an open GitHub issue on adding support for adding elements to the normal and advanced “page settings” dialogues.

👤Flimm

6đź‘Ť

There’s also a way to do this without using an inline, and having the fields anywhere on the Page form. For example, I have a custom setting for “color scheme” that I wanted to be under the “Basic Settings” fieldset. This can be done by overriding the ModelForm and the ModelAdmin’s fieldsets. Also, I opted for a OneToOne field instead of a ForeignKey, for simplicity’s sake.

models.py:

from django.db import models
from cms.models.pagemodel import Page
from django.conf import settings

class PageCustomSettings(models.Model):
    page = models.OneToOneField(Page, editable=False, 
                                related_name='custom_settings')
    color_scheme = models.CharField(blank=True, choices=settings.COLOR_SCHEMES,
                                    max_length=20)

admin.py:

from django import forms
from django.conf import settings
from django.contrib import admin
from cms.admin.pageadmin import PageAdmin, PageForm
from cms.models.pagemodel import Page
from web.models import PageCustomSettings

color_scheme_choices = (('', '---------'),) + settings.COLOR_SCHEMES

class CustomPageForm(PageForm):
    color_scheme = forms.ChoiceField(choices=color_scheme_choices,
                                     required=False)

    def __init__(self, *args, **kwargs):
        # make sure that when we're changing a current instance, to set the 
        # initial values for our custom fields
        obj = kwargs.get('instance')
        if obj:
            try:
                opts = obj.custom_settings
                kwargs['initial'] = {
                    'color_scheme': opts.color_scheme
                }
            except PageCustomSettings.DoesNotExist:
                pass
        super(CustomPageForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        # set the custom field values when saving the form
        obj = super(CustomPageForm, self).save(commit)
        try:
            opts = PageCustomSettings.objects.get(page=obj)
        except PageCustomSettings.DoesNotExist:
            opts = PageCustomSettings(page=obj)
        opts.color_scheme = self.cleaned_data['color_scheme']
        opts.save()
        return obj

PageAdmin.form = CustomPageForm
PageAdmin.fieldsets[1][1]['fields'] += ['color_scheme']

admin.site.unregister(Page)
admin.site.register(Page, PageAdmin)
👤Ben Davis

6đź‘Ť

I’ve got here via Google and the answers got me on the right track for Django CMS 3 Beta. To extend the page model and hook your extension into the toolbar, you can follow along the official documentation:

http://django-cms.readthedocs.org/en/latest/how_to/extending_page_title.html

Access value in template

{{ request.current_page.<your_model_class_name_in_lowercase>.<field_name> }}

For example, I extended the page model with this model:

from django.db import models

from cms.extensions import PageExtension
from cms.extensions.extension_pool import extension_pool


class ShowDefaultHeaderExtension(PageExtension):
    show_header = models.BooleanField(default=True)

extension_pool.register(ShowDefaultHeaderExtension)

To access its values in the template:

{{ request.current_page.showdefaultheaderextension.show_header }}
👤sthzg

4đź‘Ť

Since I dont have enough reputation I cannot comment on Timmy O’Mahony’s Post directly. However I want to note that the proposed solution of adding a StackedInline Object to the PageAdmin.inlines list does not work any more as supposed.

I’m working with Djangocms 3.3 and somewhere between Timmy O’Mahony’s version any mine the authors changed the semantic of the inline List. It’s content is now shown in the Permissions Menu for that specific page (including possibly added futher StackedInline or TabularInline items).

👤K Moe

Leave a comment