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.text import Truncator
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from .models import Page, Config
|
from .models import Config
|
||||||
|
|
||||||
@admin.register(Page)
|
class BasePageAdmin(admin.ModelAdmin):
|
||||||
class PageAdmin(admin.ModelAdmin):
|
|
||||||
prepopulated_fields = {'slug': ('title',)}
|
prepopulated_fields = {'slug': ('title',)}
|
||||||
|
|
||||||
class BaseSectionAdmin(admin.ModelAdmin):
|
class BaseSectionAdmin(admin.ModelAdmin):
|
||||||
|
|
11
cms/forms.py
11
cms/forms.py
|
@ -1,8 +1,8 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from .models import Page
|
|
||||||
|
|
||||||
import swapper
|
import swapper
|
||||||
|
Page = swapper.load_model('cms', 'Page')
|
||||||
Section = swapper.load_model('cms', 'Section')
|
Section = swapper.load_model('cms', 'Section')
|
||||||
|
|
||||||
class PageForm(forms.ModelForm):
|
class PageForm(forms.ModelForm):
|
||||||
|
@ -11,6 +11,13 @@ class PageForm(forms.ModelForm):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
class SectionForm(forms.ModelForm):
|
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):
|
def save(self):
|
||||||
section = super().save()
|
section = super().save()
|
||||||
app_label = section._meta.app_label
|
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
|
# id to the 'polymorphic_ctype_id' field. This way, the next
|
||||||
# time the object is requested from the database,
|
# time the object is requested from the database,
|
||||||
# django-polymorphic will automatically convert it to the
|
# django-polymorphic will automatically convert it to the
|
||||||
# correct subclass. Brilliant!
|
# correct subclass.
|
||||||
section.polymorphic_ctype = ContentType.objects.get(
|
section.polymorphic_ctype = ContentType.objects.get(
|
||||||
app_label=section._meta.app_label,
|
app_label=section._meta.app_label,
|
||||||
model=section.type.lower(),
|
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 ckeditor.fields
|
||||||
|
import cms.models
|
||||||
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import embed_video.fields
|
import embed_video.fields
|
||||||
|
@ -15,6 +17,23 @@ class Migration(migrations.Migration):
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
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(
|
migrations.CreateModel(
|
||||||
name='Config',
|
name='Config',
|
||||||
fields=[
|
fields=[
|
||||||
|
@ -28,38 +47,27 @@ class Migration(migrations.Migration):
|
||||||
'ordering': ['parameter'],
|
'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(
|
migrations.CreateModel(
|
||||||
name='Section',
|
name='Section',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||||
('title', models.CharField(blank=True, max_length=255, verbose_name='title')),
|
('title', cms.models.VarCharField(blank=True, verbose_name='title')),
|
||||||
('type', models.CharField(choices=[('normal', 'Normaal')], default='normal', max_length=16, verbose_name='section type')),
|
|
||||||
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')),
|
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')),
|
||||||
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
|
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
|
||||||
('image', models.ImageField(blank=True, upload_to='', verbose_name='image')),
|
('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')),
|
('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_text', cms.models.VarCharField(blank=True, verbose_name='button text')),
|
||||||
('button_link', models.CharField(blank=True, max_length=255, verbose_name='button link')),
|
('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='cms.Page', verbose_name='page')),
|
('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')),
|
('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={
|
options={
|
||||||
|
'verbose_name': 'section',
|
||||||
|
'verbose_name_plural': 'sections',
|
||||||
|
'ordering': ['position'],
|
||||||
|
'abstract': False,
|
||||||
'swappable': 'CMS_SECTION_MODEL',
|
'swappable': 'CMS_SECTION_MODEL',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
import swapper
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
Page = swapper.load_model('cms', 'Page')
|
||||||
|
|
||||||
def add_homepage(apps, schema_editor):
|
def add_homepage(apps, schema_editor):
|
||||||
Page = apps.get_model('cms', 'Page')
|
|
||||||
if not Page.objects.exists():
|
if not Page.objects.exists():
|
||||||
Page(slug='', title='Homepage', position=1).save()
|
Page(slug='', title='Homepage', position=1).save()
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('cms', '0001_initial'),
|
('cms', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,7 +2,7 @@ import swapper
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.conf import settings
|
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 django.utils.translation import gettext_lazy as _
|
||||||
from ckeditor.fields import RichTextField
|
from ckeditor.fields import RichTextField
|
||||||
from embed_video.fields import EmbedVideoField
|
from embed_video.fields import EmbedVideoField
|
||||||
|
@ -10,14 +10,25 @@ from polymorphic.models import PolymorphicModel
|
||||||
|
|
||||||
from numberedmodel.models import NumberedModel
|
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):
|
class VarCharField(models.TextField):
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
kwargs.update({'widget': TextInput})
|
kwargs.update({'widget': TextInput})
|
||||||
return super().formfield(**kwargs)
|
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)
|
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)
|
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)
|
menu = models.BooleanField(_('visible in menu'), default=True)
|
||||||
|
|
||||||
|
@ -29,29 +40,28 @@ class Page(NumberedModel):
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
if self.slug:
|
if self.slug:
|
||||||
return reverse(settings.PAGE_URL_PATTERN, args=[self.slug])
|
return reverse('cms:page', args=[self.slug])
|
||||||
else:
|
else:
|
||||||
return reverse(settings.PAGE_URL_PATTERN)
|
return reverse('cms:page')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
abstract = True
|
||||||
verbose_name = _('Page')
|
verbose_name = _('Page')
|
||||||
verbose_name_plural = _('Pages')
|
verbose_name_plural = _('Pages')
|
||||||
ordering = ['position']
|
ordering = ['position']
|
||||||
|
|
||||||
choices = settings.SECTION_TYPES
|
|
||||||
class BaseSection(NumberedModel, PolymorphicModel):
|
class BaseSection(NumberedModel, PolymorphicModel):
|
||||||
page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
|
TYPES = []
|
||||||
type = models.CharField(_('section type'), max_length=16, default=choices[0][0], choices=choices)
|
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)
|
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)
|
color = models.PositiveIntegerField(_('color'), default=1, choices=settings.SECTION_COLORS)
|
||||||
|
|
||||||
content = RichTextField(_('content'), blank=True)
|
content = RichTextField(_('content'), blank=True)
|
||||||
image = models.ImageField(_('image'), blank=True)
|
image = models.ImageField(_('image'), blank=True)
|
||||||
video = EmbedVideoField(_('video'), blank=True, help_text=_('Paste a YouTube, Vimeo, or SoundCloud link'))
|
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_text = VarCharField(_('button text'), blank=True)
|
||||||
button_link = models.CharField(_('button link'), max_length=255, blank=True)
|
button_link = VarCharField(_('button link'), blank=True)
|
||||||
|
|
||||||
def number_with_respect_to(self):
|
def number_with_respect_to(self):
|
||||||
return self.page.sections.all()
|
return self.page.sections.all()
|
||||||
|
@ -69,10 +79,13 @@ class BaseSection(NumberedModel, PolymorphicModel):
|
||||||
verbose_name = _('section')
|
verbose_name = _('section')
|
||||||
verbose_name_plural = _('sections')
|
verbose_name_plural = _('sections')
|
||||||
ordering = ['position']
|
ordering = ['position']
|
||||||
#app_label = 'cms'
|
|
||||||
|
class Page(BasePage):
|
||||||
|
class Meta(BasePage.Meta):
|
||||||
|
swappable = swapper.swappable_setting('cms', 'Page')
|
||||||
|
|
||||||
class Section(BaseSection):
|
class Section(BaseSection):
|
||||||
class Meta:
|
class Meta(BaseSection.Meta):
|
||||||
swappable = swapper.swappable_setting('cms', 'Section')
|
swappable = swapper.swappable_setting('cms', 'Section')
|
||||||
|
|
||||||
class Config(models.Model):
|
class Config(models.Model):
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
{% if pages %}
|
{% if pages %}
|
||||||
<ul id="menu">
|
<ul id="menu">
|
||||||
{% for p in pages %}
|
{% 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 %}
|
{% endfor %}
|
||||||
{% if user.is_staff %}
|
{% if user.is_staff %}
|
||||||
<li><a class="edit" href="{% url 'cms:createpage' %}">+ {% trans 'new page' %}</a></li>
|
<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 */
|
/* Only show relevant fields */
|
||||||
|
|
||||||
if (typefield) {
|
if (typefield) {
|
||||||
|
@ -99,5 +100,6 @@
|
||||||
});
|
});
|
||||||
show_relevant_fields(typefield.value.toLowerCase());
|
show_relevant_fields(typefield.value.toLowerCase());
|
||||||
}
|
}
|
||||||
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
107
cms/views.py
107
cms/views.py
|
@ -1,87 +1,38 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
|
|
||||||
from .models import Page
|
|
||||||
from .forms import PageForm, SectionForm
|
from .forms import PageForm, SectionForm
|
||||||
from .utils import get_config
|
from .utils import get_config
|
||||||
|
|
||||||
import swapper
|
import swapper
|
||||||
|
Page = swapper.load_model('cms', 'Page')
|
||||||
Section = swapper.load_model('cms', 'Section')
|
Section = swapper.load_model('cms', 'Section')
|
||||||
|
|
||||||
class StaffRequiredMixin(UserPassesTestMixin):
|
class StaffRequiredMixin(UserPassesTestMixin):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
return self.request.user.is_staff
|
return self.request.user.is_staff
|
||||||
|
|
||||||
class MenuMixin(object):
|
class MenuMixin:
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
pages = Page.objects.filter(menu=True)
|
pages = Page.objects.filter(menu=True)
|
||||||
footer = get_config(10)
|
footer = get_config(10)
|
||||||
context.update({
|
context.update({
|
||||||
'page_url_pattern': settings.PAGE_URL_PATTERN,
|
|
||||||
'pages': pages,
|
'pages': pages,
|
||||||
'footer': footer,
|
'footer': footer,
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
class MemoryMixin(object):
|
class TypeMixin(MenuMixin):
|
||||||
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
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**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 = {}
|
fields_per_type = {}
|
||||||
for model, desc in section_types:
|
for model, desc in Section.TYPES:
|
||||||
ctype = ContentType.objects.get(
|
ctype = ContentType.objects.get(
|
||||||
app_label=Section._meta.app_label,
|
app_label=Section._meta.app_label,
|
||||||
model=model.lower(),
|
model=model.lower(),
|
||||||
|
@ -93,14 +44,60 @@ class BaseUpdateView(StaffRequiredMixin, MenuMixin, generic.UpdateView):
|
||||||
})
|
})
|
||||||
return context
|
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):
|
def form_valid(self, form):
|
||||||
form.save()
|
form.save()
|
||||||
return redirect(self.request.session.get('previous_url'))
|
return redirect(self.request.session.get('previous_url'))
|
||||||
|
|
||||||
class UpdatePage(BaseUpdateView):
|
class UpdatePage(StaffRequiredMixin, MenuMixin, BaseUpdateView):
|
||||||
model = Page
|
model = Page
|
||||||
form_class = PageForm
|
form_class = PageForm
|
||||||
|
|
||||||
class UpdateSection(BaseUpdateView):
|
class UpdateSection(StaffRequiredMixin, TypeMixin, BaseUpdateView):
|
||||||
model = Section
|
model = Section
|
||||||
form_class = SectionForm
|
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 ckeditor.fields
|
||||||
|
import cms.models
|
||||||
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import embed_video.fields
|
import embed_video.fields
|
||||||
|
@ -11,25 +13,41 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.CMS_PAGE_MODEL),
|
||||||
('contenttypes', '0002_remove_content_type_name'),
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
('cms', '0001_initial'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Section',
|
name='Page',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
|
||||||
('title', models.CharField(blank=True, max_length=255, verbose_name='title')),
|
('title', cms.models.VarCharField(verbose_name='title')),
|
||||||
('type', models.CharField(choices=[('normal', 'Normaal')], default='normal', max_length=16, verbose_name='section type')),
|
('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')),
|
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')),
|
||||||
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
|
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
|
||||||
('image', models.ImageField(blank=True, upload_to='', verbose_name='image')),
|
('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')),
|
('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_text', cms.models.VarCharField(blank=True, verbose_name='button text')),
|
||||||
('button_link', models.CharField(blank=True, max_length=255, verbose_name='button link')),
|
('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='cms.Page', verbose_name='page')),
|
('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')),
|
('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={
|
options={
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
from cms.models import BaseSection
|
from cms.models import *
|
||||||
|
|
||||||
class Section(BaseSection):
|
class Page(BasePage):
|
||||||
'''Add custom fields here. Already existing fields: title, color,
|
'''Add custom fields here. Already existing fields: position, title,
|
||||||
content, image, video, button_text, button_link
|
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):
|
class TextSection(Section):
|
||||||
fields = ['type', 'position', 'title', 'content']
|
fields = ['type', 'position', 'title', 'content']
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
@register('Afbeelding')
|
||||||
class ImageSection(Section):
|
class ImageSection(Section):
|
||||||
fields = ['type', 'position', 'title', 'image']
|
fields = ['type', 'position', 'title', 'image']
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -21,7 +21,6 @@ STATIC_ROOT = '/srv/' + PROJECT_NAME + '/static'
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
MEDIA_ROOT = '/srv/' + PROJECT_NAME + '/media'
|
MEDIA_ROOT = '/srv/' + PROJECT_NAME + '/media'
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = '/'
|
||||||
PAGE_URL_PATTERN = 'cms:page'
|
|
||||||
CMS_SECTION_MODEL = 'app.Section'
|
CMS_SECTION_MODEL = 'app.Section'
|
||||||
|
|
||||||
def read(file):
|
def read(file):
|
||||||
|
|
Ładowanie…
Reference in New Issue