kopia lustrzana https://github.com/rtts/django-simplecms
Automatic detection of available section types
Use the decorator @register to register your own Section child models, and use their fields attribute to specify which fields it uses.readwriteweb
rodzic
646311335b
commit
a69d51a0dc
|
@ -2,10 +2,9 @@ from django.contrib import admin
|
|||
from django.utils.text import Truncator
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from .models import Page, Config
|
||||
from .models import Config
|
||||
|
||||
@admin.register(Page)
|
||||
class PageAdmin(admin.ModelAdmin):
|
||||
class BasePageAdmin(admin.ModelAdmin):
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
|
||||
class BaseSectionAdmin(admin.ModelAdmin):
|
||||
|
|
11
cms/forms.py
11
cms/forms.py
|
@ -1,8 +1,8 @@
|
|||
from django import forms
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from .models import Page
|
||||
|
||||
import swapper
|
||||
Page = swapper.load_model('cms', 'Page')
|
||||
Section = swapper.load_model('cms', 'Section')
|
||||
|
||||
class PageForm(forms.ModelForm):
|
||||
|
@ -11,6 +11,13 @@ class PageForm(forms.ModelForm):
|
|||
fields = '__all__'
|
||||
|
||||
class SectionForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Repopulate the 'choices' attribute of the type field from
|
||||
# the child model.
|
||||
self.fields['type'].choices = self._meta.model.TYPES
|
||||
|
||||
def save(self):
|
||||
section = super().save()
|
||||
app_label = section._meta.app_label
|
||||
|
@ -21,7 +28,7 @@ class SectionForm(forms.ModelForm):
|
|||
# id to the 'polymorphic_ctype_id' field. This way, the next
|
||||
# time the object is requested from the database,
|
||||
# django-polymorphic will automatically convert it to the
|
||||
# correct subclass. Brilliant!
|
||||
# correct subclass.
|
||||
section.polymorphic_ctype = ContentType.objects.get(
|
||||
app_label=section._meta.app_label,
|
||||
model=section.type.lower(),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# Generated by Django 3.0.1 on 2019-12-31 11:15
|
||||
# Generated by Django 3.0.1 on 2020-01-02 00:14
|
||||
|
||||
import ckeditor.fields
|
||||
import cms.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import embed_video.fields
|
||||
|
@ -15,6 +17,23 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Page',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||
('title', cms.models.VarCharField(verbose_name='title')),
|
||||
('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')),
|
||||
('menu', models.BooleanField(default=True, verbose_name='visible in menu')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Page',
|
||||
'verbose_name_plural': 'Pages',
|
||||
'ordering': ['position'],
|
||||
'abstract': False,
|
||||
'swappable': 'CMS_PAGE_MODEL',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Config',
|
||||
fields=[
|
||||
|
@ -28,38 +47,27 @@ class Migration(migrations.Migration):
|
|||
'ordering': ['parameter'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Page',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||
('title', models.CharField(max_length=255, verbose_name='title')),
|
||||
('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')),
|
||||
('menu', models.BooleanField(default=True, verbose_name='visible in menu')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Page',
|
||||
'verbose_name_plural': 'Pages',
|
||||
'ordering': ['position'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Section',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('type', cms.models.VarCharChoiceField(choices=[('textsection', 'Tekst'), ('stepsection', 'Stappenplan'), ('uploadsection', 'Upload')], default='', verbose_name='section type')),
|
||||
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||
('title', models.CharField(blank=True, max_length=255, verbose_name='title')),
|
||||
('type', models.CharField(choices=[('normal', 'Normaal')], default='normal', max_length=16, verbose_name='section type')),
|
||||
('title', cms.models.VarCharField(blank=True, verbose_name='title')),
|
||||
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')),
|
||||
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
|
||||
('image', models.ImageField(blank=True, upload_to='', verbose_name='image')),
|
||||
('video', embed_video.fields.EmbedVideoField(blank=True, help_text='Paste a YouTube, Vimeo, or SoundCloud link', verbose_name='video')),
|
||||
('button_text', models.CharField(blank=True, max_length=255, verbose_name='button text')),
|
||||
('button_link', models.CharField(blank=True, max_length=255, verbose_name='button link')),
|
||||
('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to='cms.Page', verbose_name='page')),
|
||||
('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')),
|
||||
('button_link', cms.models.VarCharField(blank=True, verbose_name='button link')),
|
||||
('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to=settings.CMS_PAGE_MODEL, verbose_name='page')),
|
||||
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_cms.section_set+', to='contenttypes.ContentType')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'section',
|
||||
'verbose_name_plural': 'sections',
|
||||
'ordering': ['position'],
|
||||
'abstract': False,
|
||||
'swappable': 'CMS_SECTION_MODEL',
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import swapper
|
||||
from django.db import migrations
|
||||
Page = swapper.load_model('cms', 'Page')
|
||||
|
||||
def add_homepage(apps, schema_editor):
|
||||
Page = apps.get_model('cms', 'Page')
|
||||
if not Page.objects.exists():
|
||||
Page(slug='', title='Homepage', position=1).save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cms', '0001_initial'),
|
||||
]
|
||||
|
|
|
@ -2,7 +2,7 @@ import swapper
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.conf import settings
|
||||
from django.forms import TextInput
|
||||
from django.forms import TextInput, Select
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from ckeditor.fields import RichTextField
|
||||
from embed_video.fields import EmbedVideoField
|
||||
|
@ -10,14 +10,25 @@ from polymorphic.models import PolymorphicModel
|
|||
|
||||
from numberedmodel.models import NumberedModel
|
||||
|
||||
def register(verbose_name):
|
||||
def wrapper(model):
|
||||
model.__bases__[-1].TYPES.append((model.__name__.lower(), verbose_name))
|
||||
return model
|
||||
return wrapper
|
||||
|
||||
class VarCharField(models.TextField):
|
||||
def formfield(self, **kwargs):
|
||||
kwargs.update({'widget': TextInput})
|
||||
return super().formfield(**kwargs)
|
||||
|
||||
class Page(NumberedModel):
|
||||
class VarCharChoiceField(models.TextField):
|
||||
def formfield(self, **kwargs):
|
||||
kwargs.update({'widget': Select})
|
||||
return super().formfield(**kwargs)
|
||||
|
||||
class BasePage(NumberedModel):
|
||||
position = models.PositiveIntegerField(_('position'), blank=True)
|
||||
title = models.CharField(_('title'), max_length=255)
|
||||
title = VarCharField(_('title'))
|
||||
slug = models.SlugField(_('slug'), help_text=_('A short identifier to use in URLs'), blank=True, unique=True)
|
||||
menu = models.BooleanField(_('visible in menu'), default=True)
|
||||
|
||||
|
@ -29,29 +40,28 @@ class Page(NumberedModel):
|
|||
|
||||
def get_absolute_url(self):
|
||||
if self.slug:
|
||||
return reverse(settings.PAGE_URL_PATTERN, args=[self.slug])
|
||||
return reverse('cms:page', args=[self.slug])
|
||||
else:
|
||||
return reverse(settings.PAGE_URL_PATTERN)
|
||||
return reverse('cms:page')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
verbose_name = _('Page')
|
||||
verbose_name_plural = _('Pages')
|
||||
ordering = ['position']
|
||||
|
||||
choices = settings.SECTION_TYPES
|
||||
class BaseSection(NumberedModel, PolymorphicModel):
|
||||
page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
|
||||
type = models.CharField(_('section type'), max_length=16, default=choices[0][0], choices=choices)
|
||||
|
||||
TYPES = []
|
||||
page = models.ForeignKey(swapper.get_model_name('cms', 'Page'), verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
|
||||
type = VarCharChoiceField(_('section type'), default='', choices=TYPES)
|
||||
position = models.PositiveIntegerField(_('position'), blank=True)
|
||||
title = models.CharField(_('title'), max_length=255, blank=True)
|
||||
title = VarCharField(_('title'), blank=True)
|
||||
color = models.PositiveIntegerField(_('color'), default=1, choices=settings.SECTION_COLORS)
|
||||
|
||||
content = RichTextField(_('content'), blank=True)
|
||||
image = models.ImageField(_('image'), blank=True)
|
||||
video = EmbedVideoField(_('video'), blank=True, help_text=_('Paste a YouTube, Vimeo, or SoundCloud link'))
|
||||
button_text = models.CharField(_('button text'), max_length=255, blank=True)
|
||||
button_link = models.CharField(_('button link'), max_length=255, blank=True)
|
||||
button_text = VarCharField(_('button text'), blank=True)
|
||||
button_link = VarCharField(_('button link'), blank=True)
|
||||
|
||||
def number_with_respect_to(self):
|
||||
return self.page.sections.all()
|
||||
|
@ -69,10 +79,13 @@ class BaseSection(NumberedModel, PolymorphicModel):
|
|||
verbose_name = _('section')
|
||||
verbose_name_plural = _('sections')
|
||||
ordering = ['position']
|
||||
#app_label = 'cms'
|
||||
|
||||
class Page(BasePage):
|
||||
class Meta(BasePage.Meta):
|
||||
swappable = swapper.swappable_setting('cms', 'Page')
|
||||
|
||||
class Section(BaseSection):
|
||||
class Meta:
|
||||
class Meta(BaseSection.Meta):
|
||||
swappable = swapper.swappable_setting('cms', 'Section')
|
||||
|
||||
class Config(models.Model):
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
{% if pages %}
|
||||
<ul id="menu">
|
||||
{% for p in pages %}
|
||||
<li><a href="{% if p.slug %}{% url page_url_pattern p.slug %}{% else %}{% url page_url_pattern %}{% endif %}" {% if p.pk == page.pk %}class="current"{% endif %}>{{p.title}}</a></li>
|
||||
<li><a href="{% if p.slug %}{% url 'cms:page' p.slug %}{% else %}{% url 'cms:page' %}{% endif %}" {% if p.pk == page.pk %}class="current"{% endif %}>{{p.title}}</a></li>
|
||||
{% endfor %}
|
||||
{% if user.is_staff %}
|
||||
<li><a class="edit" href="{% url 'cms:createpage' %}">+ {% trans 'new page' %}</a></li>
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
{% if fields_per_type %}
|
||||
/* Only show relevant fields */
|
||||
|
||||
if (typefield) {
|
||||
|
@ -99,5 +100,6 @@
|
|||
});
|
||||
show_relevant_fields(typefield.value.toLowerCase());
|
||||
}
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
107
cms/views.py
107
cms/views.py
|
@ -1,87 +1,38 @@
|
|||
import json
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.views import generic
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
|
||||
from .models import Page
|
||||
from .forms import PageForm, SectionForm
|
||||
from .utils import get_config
|
||||
|
||||
import swapper
|
||||
Page = swapper.load_model('cms', 'Page')
|
||||
Section = swapper.load_model('cms', 'Section')
|
||||
|
||||
class StaffRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.is_staff
|
||||
|
||||
class MenuMixin(object):
|
||||
class MenuMixin:
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
pages = Page.objects.filter(menu=True)
|
||||
footer = get_config(10)
|
||||
context.update({
|
||||
'page_url_pattern': settings.PAGE_URL_PATTERN,
|
||||
'pages': pages,
|
||||
'footer': footer,
|
||||
})
|
||||
return context
|
||||
|
||||
class MemoryMixin(object):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.user.is_authenticated:
|
||||
request.session['previous_url'] = request.path
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
class BasePageView(MenuMixin, MemoryMixin, generic.DetailView):
|
||||
model = Page
|
||||
template_name = 'cms/page.html'
|
||||
|
||||
def setup(self, request, *args, slug='', **kwargs):
|
||||
self.request = request
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.kwargs['slug'] = slug
|
||||
|
||||
class TypeMixin(MenuMixin):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
page = self.object
|
||||
sections = page.sections.all()
|
||||
context.update({
|
||||
'page': page,
|
||||
'sections': sections,
|
||||
})
|
||||
return context
|
||||
|
||||
class PageView(BasePageView):
|
||||
pass
|
||||
|
||||
class CreatePage(StaffRequiredMixin, MenuMixin, generic.CreateView):
|
||||
model = Page
|
||||
form_class = PageForm
|
||||
template_name = 'cms/new.html'
|
||||
|
||||
class CreateSection(StaffRequiredMixin, MenuMixin, generic.CreateView):
|
||||
model = Section
|
||||
form_class = SectionForm
|
||||
template_name = 'cms/new.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.page = Page.objects.get(pk=self.kwargs.get('pk'))
|
||||
form.save()
|
||||
return redirect(self.request.session.get('previous_url'))
|
||||
|
||||
class BaseUpdateView(StaffRequiredMixin, MenuMixin, generic.UpdateView):
|
||||
template_name = 'cms/edit.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
section_types = settings.SECTION_TYPES
|
||||
fields_per_type = {}
|
||||
for model, desc in section_types:
|
||||
for model, desc in Section.TYPES:
|
||||
ctype = ContentType.objects.get(
|
||||
app_label=Section._meta.app_label,
|
||||
model=model.lower(),
|
||||
|
@ -93,14 +44,60 @@ class BaseUpdateView(StaffRequiredMixin, MenuMixin, generic.UpdateView):
|
|||
})
|
||||
return context
|
||||
|
||||
class MemoryMixin:
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.user.is_authenticated:
|
||||
request.session['previous_url'] = request.path
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
class PageView(MenuMixin, MemoryMixin, generic.DetailView):
|
||||
model = Page
|
||||
template_name = 'cms/page.html'
|
||||
|
||||
# Supplies a default argument for slug
|
||||
def setup(self, *args, slug='', **kwargs):
|
||||
super().setup(*args, slug=slug, **kwargs)
|
||||
#self.request = request
|
||||
#self.args = args
|
||||
#self.kwargs = kwargs
|
||||
#self.kwargs['slug'] = slug
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
page = self.object
|
||||
sections = page.sections.all()
|
||||
context.update({
|
||||
'page': page,
|
||||
'sections': sections,
|
||||
})
|
||||
return context
|
||||
|
||||
class BaseUpdateView(generic.UpdateView):
|
||||
template_name = 'cms/edit.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
return redirect(self.request.session.get('previous_url'))
|
||||
|
||||
class UpdatePage(BaseUpdateView):
|
||||
class UpdatePage(StaffRequiredMixin, MenuMixin, BaseUpdateView):
|
||||
model = Page
|
||||
form_class = PageForm
|
||||
|
||||
class UpdateSection(BaseUpdateView):
|
||||
class UpdateSection(StaffRequiredMixin, TypeMixin, BaseUpdateView):
|
||||
model = Section
|
||||
form_class = SectionForm
|
||||
|
||||
class CreatePage(StaffRequiredMixin, MenuMixin, generic.CreateView):
|
||||
model = Page
|
||||
form_class = PageForm
|
||||
template_name = 'cms/new.html'
|
||||
|
||||
class CreateSection(StaffRequiredMixin, TypeMixin, generic.CreateView):
|
||||
model = Section
|
||||
form_class = SectionForm
|
||||
template_name = 'cms/new.html'
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.page = Page.objects.get(pk=self.kwargs.get('pk'))
|
||||
form.save()
|
||||
return redirect(self.request.session.get('previous_url'))
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
from django.contrib import admin
|
||||
from cms.admin import BaseSectionAdmin
|
||||
from .models import Section
|
||||
|
||||
@admin.register(Section)
|
||||
class SectionAdmin(BaseSectionAdmin):
|
||||
pass
|
|
@ -1,6 +1,8 @@
|
|||
# Generated by Django 3.0.1 on 2019-12-31 11:16
|
||||
# Generated by Django 3.0.1 on 2020-01-02 00:06
|
||||
|
||||
import ckeditor.fields
|
||||
import cms.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import embed_video.fields
|
||||
|
@ -11,25 +13,41 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.CMS_PAGE_MODEL),
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('cms', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Section',
|
||||
name='Page',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||
('title', models.CharField(blank=True, max_length=255, verbose_name='title')),
|
||||
('type', models.CharField(choices=[('normal', 'Normaal')], default='normal', max_length=16, verbose_name='section type')),
|
||||
('title', cms.models.VarCharField(verbose_name='title')),
|
||||
('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')),
|
||||
('menu', models.BooleanField(default=True, verbose_name='visible in menu')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Page',
|
||||
'verbose_name_plural': 'Pages',
|
||||
'ordering': ['position'],
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Section',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('type', cms.models.VarCharChoiceField(choices=[('textsection', 'Tekst'), ('imagesection', 'Afbeelding')], default='', verbose_name='section type')),
|
||||
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||
('title', cms.models.VarCharField(blank=True, verbose_name='title')),
|
||||
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')),
|
||||
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
|
||||
('image', models.ImageField(blank=True, upload_to='', verbose_name='image')),
|
||||
('video', embed_video.fields.EmbedVideoField(blank=True, help_text='Paste a YouTube, Vimeo, or SoundCloud link', verbose_name='video')),
|
||||
('button_text', models.CharField(blank=True, max_length=255, verbose_name='button text')),
|
||||
('button_link', models.CharField(blank=True, max_length=255, verbose_name='button link')),
|
||||
('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to='cms.Page', verbose_name='page')),
|
||||
('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')),
|
||||
('button_link', cms.models.VarCharField(blank=True, verbose_name='button link')),
|
||||
('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to=settings.CMS_PAGE_MODEL, verbose_name='page')),
|
||||
('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_app.section_set+', to='contenttypes.ContentType')),
|
||||
],
|
||||
options={
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
from cms.models import BaseSection
|
||||
from cms.models import *
|
||||
|
||||
class Section(BaseSection):
|
||||
'''Add custom fields here. Already existing fields: title, color,
|
||||
content, image, video, button_text, button_link
|
||||
class Page(BasePage):
|
||||
'''Add custom fields here. Already existing fields: position, title,
|
||||
slug, menu
|
||||
|
||||
'''
|
||||
|
||||
class Section(BaseSection):
|
||||
'''Add custom fields here. Already existing fields: type, position,
|
||||
title, color, content, image, video, button_text, button_link
|
||||
|
||||
'''
|
||||
|
||||
@register('Tekst')
|
||||
class TextSection(Section):
|
||||
fields = ['type', 'position', 'title', 'content']
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
@register('Afbeelding')
|
||||
class ImageSection(Section):
|
||||
fields = ['type', 'position', 'title', 'image']
|
||||
class Meta:
|
||||
|
|
|
@ -21,7 +21,6 @@ STATIC_ROOT = '/srv/' + PROJECT_NAME + '/static'
|
|||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = '/srv/' + PROJECT_NAME + '/media'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
PAGE_URL_PATTERN = 'cms:page'
|
||||
CMS_SECTION_MODEL = 'app.Section'
|
||||
|
||||
def read(file):
|
||||
|
|
Ładowanie…
Reference in New Issue