I would like to add some extra fields to pages in django-cms (in django admin panel). How do this in the simplest way?
-
do you want to show those fields in admin and those fields already exist in the model? Or you want to add new fields to the existing models? – kender Apr 24 '12 at 08:11
-
@kender - a new one.. I still need help:) – pmoniq Apr 24 '12 at 08:13
-
you can add those fields to CMS's model, can't you? then create a schemamigration (think Django-cms uses South for that). Then all it's left is to modify / monkeypatch the ModelAdmin classes for the changed models... – kender Apr 24 '12 at 08:33
5 Answers
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/

- 16,603
- 16
- 90
- 84

- 53,000
- 18
- 155
- 177
-
4Please note that as I have commented in my blog post the context processor is not required if you access the data via the Page objects itself. Maybe Timmy's way is more clear cause you won't need to write the whole "request.current_page.extended_fields.all..." stuff in the template but for me it is an extra overload that I would like to skip if I don't need it for all pages. Generally it is a matter of coding style. – Ilian Iliev Jan 15 '13 at 15:26
-
4They are now using `request.current_page.publisher_draft.extended_fields.page_image` in > 2.4 [sof ref](http://stackoverflow.com/a/16852790/707580). I think this is helpful to people from Google like me. – hbrls Nov 12 '13 at 06:37
-
For some reason, I can't get `ExtendedPageAdmin` to appear in the admin interface. – Flimm Aug 11 '16 at 10:28
There is an official way to extend the page & title models, I highly recommend this official documentation:
- Extending the page & title models from docs.django-cms.org
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:
Create a subclass of
PageExtension
in yourmodels.py
file and register it:class IconExtension(PageExtension): image = models.ImageField(upload_to='icons') extension_pool.register(IconExtension)
Create also a subclass of
PageExtensionAdmin
in youradmin.py
file and register it:class IconExtensionAdmin(PageExtensionAdmin): pass admin.site.register(IconExtension, IconExtensionAdmin)
Finally, to make it accessible from the toolbar, create a subclass of
ExtensionToolbar
incms_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.
-
Definitely the newer, easier, simpler, and better way - I had missed this addition somehow. Thank you! – The NetYeti Apr 27 '17 at 17:55
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)

- 13,112
- 10
- 50
- 65
-
-
Very nice solution although when I publish my page in the CMS this creates a new page not copying the new properties over to the published page. – Daniel Tate Apr 22 '14 at 21:46
-
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 }}

- 5,514
- 2
- 29
- 50
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).

- 802
- 1
- 7
- 4