First draft of version 2.0.0

Oh boy! This is a big one. Two new dependencies: swapper and
django-polymorphic will now allow any project that uses cms to elegantly
extend the default Section model with custom fields and custom subclasses.
This is still a work in progress.
readwriteweb
Jaap Joris Vens 2019-12-31 13:05:12 +01:00
rodzic 4004643dea
commit d166e10b05
29 zmienionych plików z 264 dodań i 170 usunięć

Wyświetl plik

@ -2,36 +2,18 @@ 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, Section, SubSection, Config from .models import Page, Config
class InlineSectionAdmin(admin.StackedInline):
model = Section
extra = 0
class InlineSubSectionAdmin(admin.StackedInline):
model = SubSection
extra = 0
@admin.register(Page) @admin.register(Page)
class PageAdmin(admin.ModelAdmin): class PageAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)} prepopulated_fields = {'slug': ('title',)}
inlines = [InlineSectionAdmin]
@admin.register(Section) class BaseSectionAdmin(admin.ModelAdmin):
class SectionAdmin(admin.ModelAdmin):
inlines = [InlineSubSectionAdmin]
list_filter = [ list_filter = [
('page', admin.RelatedOnlyFieldListFilter), ('page', admin.RelatedOnlyFieldListFilter),
] ]
list_display = ['__str__', 'get_type_display'] list_display = ['__str__', 'get_type_display']
@admin.register(SubSection)
class SubSectionAdmin(admin.ModelAdmin):
list_filter = [
('section', admin.RelatedOnlyFieldListFilter),
('section__page', admin.RelatedOnlyFieldListFilter),
]
@admin.register(Config) @admin.register(Config)
class ConfigAdmin(admin.ModelAdmin): class ConfigAdmin(admin.ModelAdmin):
list_display = ['__str__', 'get_content'] list_display = ['__str__', 'get_content']

Wyświetl plik

@ -1,5 +1,9 @@
from django import forms from django import forms
from .models import Page, Section, SubSection from django.contrib.contenttypes.models import ContentType
from .models import Page
import swapper
Section = swapper.load_model('cms', 'Section')
class PageForm(forms.ModelForm): class PageForm(forms.ModelForm):
class Meta: class Meta:
@ -7,14 +11,25 @@ class PageForm(forms.ModelForm):
fields = '__all__' fields = '__all__'
class SectionForm(forms.ModelForm): class SectionForm(forms.ModelForm):
def save(self):
section = super().save()
app_label = section._meta.app_label
model = section.type
# Explanation: we'll get the content type of the model that
# the user supplied when filling in this form, and save it's
# 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!
section.polymorphic_ctype = ContentType.objects.get(
app_label=section._meta.app_label,
model=section.type.lower(),
)
section.save()
return section
class Meta: class Meta:
model = Section model = Section
exclude = ['page'] exclude = ['page']
class SubSectionForm(forms.ModelForm):
class Meta:
model = SubSection
exclude = ['section']
SectionFormSet = forms.inlineformset_factory(Page, Section, exclude='__all__', extra=0)
SubSectionFormSet = forms.inlineformset_factory(Section, SubSection, exclude='__all__', extra=0)

Wyświetl plik

@ -1,13 +1,17 @@
# Generated by Django 3.0.1 on 2019-12-31 11:15
import ckeditor.fields import ckeditor.fields
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
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('contenttypes', '0002_remove_content_type_name'),
] ]
operations = [ operations = [
@ -16,7 +20,7 @@ class Migration(migrations.Migration):
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')),
('parameter', models.PositiveIntegerField(choices=[(10, 'Footer')], unique=True)), ('parameter', models.PositiveIntegerField(choices=[(10, 'Footer')], unique=True)),
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='Inhoud')), ('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
], ],
options={ options={
'verbose_name': 'configuration parameter', 'verbose_name': 'configuration parameter',
@ -44,20 +48,19 @@ class Migration(migrations.Migration):
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(max_length=255, verbose_name='title')), ('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')), ('type', models.CharField(choices=[('normal', 'Normaal')], default='normal', max_length=16, verbose_name='section type')),
('color', models.PositiveIntegerField(choices=[(1, 'Licht'), (2, 'Donker')], 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', models.CharField(blank=True, max_length=255, verbose_name='button text')),
('button_link', models.CharField(blank=True, max_length=255, verbose_name='button link')), ('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')), ('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to='cms.Page', 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={ options={
'verbose_name': 'section', 'swappable': 'CMS_SECTION_MODEL',
'verbose_name_plural': 'sections',
'ordering': ['position'],
}, },
), ),
] ]

Wyświetl plik

@ -8,7 +8,7 @@ def add_homepage(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('cms', '0003_subsection'), ('cms', '0001_initial'),
] ]
operations = [ operations = [

Wyświetl plik

@ -1,15 +0,0 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cms', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='section',
name='title',
field=models.CharField(blank=True, max_length=255, verbose_name='title'),
),
]

Wyświetl plik

@ -1,32 +0,0 @@
import ckeditor.fields
import cms.models
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cms', '0002_title'),
]
operations = [
migrations.CreateModel(
name='SubSection',
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')),
('color', models.PositiveIntegerField(choices=[(1, 'Licht'), (2, 'Donker')], default=1, verbose_name='color')),
('content', ckeditor.fields.RichTextField(blank=True, verbose_name='content')),
('image', models.ImageField(blank=True, upload_to='', verbose_name='image')),
('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')),
('button_link', cms.models.VarCharField(blank=True, verbose_name='button link')),
('section', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='subsections', to='cms.Section', verbose_name='section')),
],
options={
'verbose_name': 'subsection',
'verbose_name_plural': 'subsections',
'ordering': ['position'],
},
),
]

Wyświetl plik

@ -1,3 +1,4 @@
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
@ -5,6 +6,7 @@ from django.forms import TextInput
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
from polymorphic.models import PolymorphicModel
from numberedmodel.models import NumberedModel from numberedmodel.models import NumberedModel
@ -36,11 +38,12 @@ class Page(NumberedModel):
verbose_name_plural = _('Pages') verbose_name_plural = _('Pages')
ordering = ['position'] ordering = ['position']
class Section(NumberedModel): choices = settings.SECTION_TYPES
class BaseSection(NumberedModel, PolymorphicModel):
page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT) page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
position = models.PositiveIntegerField(_('position'), blank=True) position = models.PositiveIntegerField(_('position'), blank=True)
title = models.CharField(_('title'), max_length=255, blank=True) title = models.CharField(_('title'), max_length=255, blank=True)
type = models.CharField(_('section type'), max_length=16, default=settings.SECTION_TYPES[0][0], choices=settings.SECTION_TYPES) type = models.CharField(_('section type'), max_length=16, default=choices[0][0], choices=choices)
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)
@ -61,36 +64,15 @@ class Section(NumberedModel):
return self.title return self.title
class Meta: class Meta:
abstract = True
verbose_name = _('section') verbose_name = _('section')
verbose_name_plural = _('sections') verbose_name_plural = _('sections')
ordering = ['position'] ordering = ['position']
#app_label = 'cms'
class SubSection(NumberedModel): class Section(BaseSection):
section = models.ForeignKey(Section, verbose_name=_('section'), related_name='subsections', on_delete=models.CASCADE)
position = models.PositiveIntegerField(_('position'), blank=True)
title = models.CharField(_('title'), max_length=255, blank=True)
color = models.PositiveIntegerField(_('color'), default=1, choices=settings.SECTION_COLORS)
content = RichTextField(_('content'), blank=True)
image = models.ImageField(_('image'), blank=True)
button_text = VarCharField(_('button text'), blank=True)
button_link = VarCharField(_('button link'), blank=True)
def number_with_respect_to(self):
return self.section.subsections.all()
def __str__(self):
if not self.pk:
return str(_('New subsection'))
elif not self.title:
return str(_('Untitled'))
else:
return self.title
class Meta: class Meta:
verbose_name = _('subsection') swappable = swapper.swappable_setting('cms', 'Section')
verbose_name_plural = _('subsections')
ordering = ['position']
class Config(models.Model): class Config(models.Model):
TYPES = [ TYPES = [

Wyświetl plik

@ -188,8 +188,6 @@ div.edit a, div.edit button, a.edit{
display: inline; display: inline;
background: none; background: none;
cursor: pointer; cursor: pointer;
margin: 0;
padding: 0;
&:before { &:before {
content: '[ '; content: '[ ';

Wyświetl plik

@ -140,9 +140,7 @@ div.edit a, div.edit button, a.edit {
border: none; border: none;
display: inline; display: inline;
background: none; background: none;
cursor: pointer; cursor: pointer; }
margin: 0;
padding: 0; }
div.edit a:before, div.edit button:before, a.edit:before { div.edit a:before, div.edit button:before, a.edit:before {
content: '[ '; } content: '[ '; }
div.edit a:after, div.edit button:after, a.edit:after { div.edit a:after, div.edit button:after, a.edit:after {

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -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 == object.pk %}class="current"{% endif %}>{{p.title}}</a></li> <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>
{% 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>

Wyświetl plik

@ -6,7 +6,8 @@
{% block content %} {% block content %}
{% for section in sections %} {% for section in sections %}
<section class="{{section.type}} color{{section.color}}"> <section class="{{section.type}} color{{section.color}}">
{% include 'cms/sections/'|add:section.type|add:'.html' %} DIT IS EEN SECTIE MET FIELDS: {{section.fields}}
{% include 'cms/sections/'|add:section.type|lower|add:'.html' %}
</section> </section>
{% endfor %} {% endfor %}

Wyświetl plik

@ -0,0 +1 @@
{% extends 'cms/sections/base.html' %}

Wyświetl plik

@ -1,5 +1,5 @@
from django.urls import path from django.urls import path
from .views import PageView, UpdatePage, CreatePage, UpdateSection, CreateSection, CreateSubSection from .views import PageView, UpdatePage, CreatePage, UpdateSection, CreateSection
app_name = 'cms' app_name = 'cms'
@ -9,7 +9,6 @@ urlpatterns = [
path('updatesection/<int:pk>/', UpdateSection.as_view(), name='updatesection'), path('updatesection/<int:pk>/', UpdateSection.as_view(), name='updatesection'),
path('createpage/', CreatePage.as_view(), name='createpage'), path('createpage/', CreatePage.as_view(), name='createpage'),
path('createsection/<int:pk>', CreateSection.as_view(), name='createsection'), path('createsection/<int:pk>', CreateSection.as_view(), name='createsection'),
path('createsubsection/<int:pk>/', CreateSubSection.as_view(), name='createsubsection'),
# Feel free to copy the following into your root URL conf! # Feel free to copy the following into your root URL conf!
path('', PageView.as_view(), name='page'), path('', PageView.as_view(), name='page'),

Wyświetl plik

@ -4,10 +4,13 @@ from django.shortcuts import redirect
from django.contrib.auth.mixins import UserPassesTestMixin from django.contrib.auth.mixins import UserPassesTestMixin
from django.views.generic import DetailView, UpdateView, CreateView from django.views.generic import DetailView, UpdateView, CreateView
from .models import Page, Section, SubSection from .models import Page
from .forms import PageForm, SectionFormSet, SectionForm, SubSectionFormSet, SubSectionForm from .forms import PageForm, SectionForm
from .utils import get_config from .utils import get_config
import swapper
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
@ -68,59 +71,17 @@ class CreateSection(StaffRequiredMixin, MenuMixin, CreateView):
form.save() form.save()
return redirect(self.request.session.get('previous_url')) return redirect(self.request.session.get('previous_url'))
class CreateSubSection(StaffRequiredMixin, MenuMixin, CreateView):
model = SubSection
form_class = SubSectionForm
template_name = 'cms/new.html'
def form_valid(self, form):
form.instance.section = Section.objects.get(pk=self.kwargs.get('pk'))
form.save()
return redirect(self.request.session.get('previous_url'))
class BaseUpdateView(StaffRequiredMixin, MenuMixin, UpdateView): class BaseUpdateView(StaffRequiredMixin, MenuMixin, UpdateView):
template_name = 'cms/edit.html' template_name = 'cms/edit.html'
def post(self, request, *args, **kwargs): def form_valid(self, form):
self.object = self.get_object()
form = self.get_form()
formset = self.formset_class(request.POST, request.FILES, instance=self.object)
if form.is_valid() and formset.is_valid():
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
form.save() form.save()
formset.save()
return redirect(self.request.session.get('previous_url')) return redirect(self.request.session.get('previous_url'))
def form_invalid(self, form, formset):
return self.render_to_response(self.get_context_data(form=form, formset=formset))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if 'formset' not in context:
formset = self.formset_class(instance=self.object)
context.update({
'formset': formset,
'formset_form_url': self.get_formset_form_url(self.object),
'formset_description': self.formset_class.model._meta.verbose_name,
})
return context
class UpdatePage(BaseUpdateView): class UpdatePage(BaseUpdateView):
model = Page model = Page
form_class = PageForm form_class = PageForm
formset_class = SectionFormSet
def get_formset_form_url(self, page):
return reverse('cms:createsection', args=[page.pk])
class UpdateSection(BaseUpdateView): class UpdateSection(BaseUpdateView):
model = Section model = Section
form_class = SectionForm form_class = SectionForm
formset_class = SubSectionFormSet
def get_formset_form_url(self, page):
return reverse('cms:createsubsection', args=[page.pk])

Wyświetl plik

@ -0,0 +1 @@
default_app_config = 'app.apps.Config'

Wyświetl plik

@ -0,0 +1,7 @@
from django.contrib import admin
from cms.admin import BaseSectionAdmin
from .models import Section
@admin.register(Section)
class SectionAdmin(BaseSectionAdmin):
pass

Wyświetl plik

@ -0,0 +1,4 @@
from django.apps import AppConfig
class Config(AppConfig):
name = 'app'
verbose_name = 'app'

Wyświetl plik

@ -0,0 +1,64 @@
# Generated by Django 3.0.1 on 2019-12-31 11:16
import ckeditor.fields
from django.db import migrations, models
import django.db.models.deletion
import embed_video.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('cms', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Section',
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')),
('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')),
('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={
'verbose_name': 'section',
'verbose_name_plural': 'sections',
'ordering': ['position'],
'abstract': False,
},
),
migrations.CreateModel(
name='ImageSection',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('app.section',),
),
migrations.CreateModel(
name='TextSection',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('app.section',),
),
]

Wyświetl plik

@ -0,0 +1,18 @@
from cms.models import BaseSection
class Section(BaseSection):
'''Add custom fields here. Already existing fields: title, color,
content, image, video, button_text, button_link
'''
class TextSection(Section):
fields = ['title', 'content']
class Meta:
proxy = True
class ImageSection(Section):
fields = ['title', 'image']
class Meta:
proxy = True

Wyświetl plik

@ -0,0 +1,47 @@
$small: 500px;
$medium: 800px;
$font: sans-serif;
$titlefont: sans-serif;
body {
font-family: $font;
}
h1, h2, h3, h4, h5, h6 {
margin: .5em 0;
font-family: $titlefont;
}
h1 { font-size: 2em }
h2 { font-size: 1.5em }
h3 { font-size: 1.25em }
h4, h5, h6 { font-size: 1em }
a {
&:hover {
}
}
a.button {
&:hover {
}
}
header {
h1 {
text-align: center;
}
img {
display: block;
width: 100%;
max-width: 400px;
margin: auto;
}
}
nav {
}
footer {
margin-top: 4em;
min-height: 400px;
}

Wyświetl plik

@ -0,0 +1,33 @@
body {
font-family: sans-serif; }
h1, h2, h3, h4, h5, h6 {
margin: .5em 0;
font-family: sans-serif; }
h1 {
font-size: 2em; }
h2 {
font-size: 1.5em; }
h3 {
font-size: 1.25em; }
h4, h5, h6 {
font-size: 1em; }
header h1 {
text-align: center; }
header img {
display: block;
width: 100%;
max-width: 400px;
margin: auto; }
footer {
margin-top: 4em;
min-height: 400px; }
/*# sourceMappingURL=main1.scss.css.map */

Wyświetl plik

@ -0,0 +1,9 @@
{
"version": 3,
"file": "main1.css",
"sources": [
"main1.scss"
],
"names": [],
"mappings": "AAKA,AAAA,IAAI,CAAC;EACH,WAAW,EAJN,UAAU,GAKhB;;AAED,AAAA,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;EACrB,MAAM,EAAE,MAAM;EACd,WAAW,EARD,UAAU,GASrB;;AACD,AAAA,EAAE,CAAC;EAAE,SAAS,EAAE,GAAI,GAAE;;AACtB,AAAA,EAAE,CAAC;EAAE,SAAS,EAAE,KAAM,GAAE;;AACxB,AAAA,EAAE,CAAC;EAAE,SAAS,EAAE,MAAO,GAAE;;AACzB,AAAA,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;EAAE,SAAS,EAAE,GAAI,GAAE;;AAY9B,AACE,MADI,CACJ,EAAE,CAAC;EACD,UAAU,EAAE,MAAM,GACnB;;AAHH,AAIE,MAJI,CAIJ,GAAG,CAAC;EACF,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,SAAS,EAAE,KAAK;EAChB,MAAM,EAAE,IAAI,GACb;;AAMH,AAAA,MAAM,CAAC;EACL,UAAU,EAAE,GAAG;EACf,UAAU,EAAE,KAAK,GAClB"
}

Wyświetl plik

@ -0,0 +1,13 @@
{% extends 'cms/base.html' %}
{% load static %}
{% block title %}app{% endblock %}
{% block extrahead %}
<link rel="stylesheet" href="{% static 'app/main1.scss.css' %}">
{% endblock %}
{% block header %}
<div class="wrapper">
<h1><a href="/">Awesome Website</a></h1>
</div>
{% endblock %}

Wyświetl plik

@ -5,7 +5,7 @@ try:
except ImportError: except ImportError:
DEBUG = True DEBUG = True
PROJECT_NAME = INSERT_PROJECT_NAME_HERE PROJECT_NAME = 'example'
KEYFILE = f'/tmp/{PROJECT_NAME}.secret' KEYFILE = f'/tmp/{PROJECT_NAME}.secret'
ADMINS = [('JJ Vens', 'jj@rtts.eu')] ADMINS = [('JJ Vens', 'jj@rtts.eu')]
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
@ -22,6 +22,7 @@ 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' PAGE_URL_PATTERN = 'cms:page'
CMS_SECTION_MODEL = 'app.Section'
def read(file): def read(file):
with open(file) as f: with open(file) as f:
@ -36,7 +37,8 @@ except IOError:
write(KEYFILE, SECRET_KEY) write(KEYFILE, SECRET_KEY)
SECTION_TYPES = [ SECTION_TYPES = [
('normal', 'Normaal'), ('TextSection', 'Tekst'),
('ImageSection', 'Afbeelding'),
] ]
SECTION_COLORS = [ SECTION_COLORS = [
@ -63,8 +65,7 @@ CKEDITOR_CONFIGS = {
} }
INSTALLED_APPS = [ INSTALLED_APPS = [
'simplesass', 'app',
PROJECT_NAME,
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@ -72,7 +73,9 @@ INSTALLED_APPS = [
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'cms', 'cms',
'simplesass',
'ckeditor', 'ckeditor',
'polymorphic',
'embed_video', 'embed_video',
'easy_thumbnails', 'easy_thumbnails',
'django_extensions', 'django_extensions',

Wyświetl plik

@ -3,6 +3,8 @@ Django
django-ckeditor django-ckeditor
django-extensions django-extensions
django-embed-video django-embed-video
django-polymorphic
easy-thumbnails easy-thumbnails
psycopg2 psycopg2
libsass libsass
swapper

Wyświetl plik

@ -3,7 +3,7 @@ from setuptools import setup, find_packages
setup( setup(
name = 'django-simplecms', name = 'django-simplecms',
version = '1.0.2', version = '2.0.0',
url = 'https://github.com/rtts/django-simplecms', url = 'https://github.com/rtts/django-simplecms',
author = 'Jaap Joris Vens', author = 'Jaap Joris Vens',
author_email = 'jj@rtts.eu', author_email = 'jj@rtts.eu',