kopia lustrzana https://github.com/rtts/django-simplecms
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
rodzic
4004643dea
commit
d166e10b05
22
cms/admin.py
22
cms/admin.py
|
@ -2,36 +2,18 @@ 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, Section, SubSection, Config
|
||||
|
||||
class InlineSectionAdmin(admin.StackedInline):
|
||||
model = Section
|
||||
extra = 0
|
||||
|
||||
class InlineSubSectionAdmin(admin.StackedInline):
|
||||
model = SubSection
|
||||
extra = 0
|
||||
from .models import Page, Config
|
||||
|
||||
@admin.register(Page)
|
||||
class PageAdmin(admin.ModelAdmin):
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
inlines = [InlineSectionAdmin]
|
||||
|
||||
@admin.register(Section)
|
||||
class SectionAdmin(admin.ModelAdmin):
|
||||
inlines = [InlineSubSectionAdmin]
|
||||
class BaseSectionAdmin(admin.ModelAdmin):
|
||||
list_filter = [
|
||||
('page', admin.RelatedOnlyFieldListFilter),
|
||||
]
|
||||
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)
|
||||
class ConfigAdmin(admin.ModelAdmin):
|
||||
list_display = ['__str__', 'get_content']
|
||||
|
|
33
cms/forms.py
33
cms/forms.py
|
@ -1,5 +1,9 @@
|
|||
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 Meta:
|
||||
|
@ -7,14 +11,25 @@ class PageForm(forms.ModelForm):
|
|||
fields = '__all__'
|
||||
|
||||
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:
|
||||
model = Section
|
||||
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)
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
# Generated by Django 3.0.1 on 2019-12-31 11:15
|
||||
|
||||
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'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
@ -16,7 +20,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('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={
|
||||
'verbose_name': 'configuration parameter',
|
||||
|
@ -44,20 +48,19 @@ class Migration(migrations.Migration):
|
|||
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')),
|
||||
('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, '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')),
|
||||
('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_cms.section_set+', to='contenttypes.ContentType')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'section',
|
||||
'verbose_name_plural': 'sections',
|
||||
'ordering': ['position'],
|
||||
'swappable': 'CMS_SECTION_MODEL',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -8,7 +8,7 @@ def add_homepage(apps, schema_editor):
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cms', '0003_subsection'),
|
||||
('cms', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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'],
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,3 +1,4 @@
|
|||
import swapper
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.conf import settings
|
||||
|
@ -5,6 +6,7 @@ from django.forms import TextInput
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from ckeditor.fields import RichTextField
|
||||
from embed_video.fields import EmbedVideoField
|
||||
from polymorphic.models import PolymorphicModel
|
||||
|
||||
from numberedmodel.models import NumberedModel
|
||||
|
||||
|
@ -36,11 +38,12 @@ class Page(NumberedModel):
|
|||
verbose_name_plural = _('Pages')
|
||||
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)
|
||||
position = models.PositiveIntegerField(_('position'), 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)
|
||||
|
||||
content = RichTextField(_('content'), blank=True)
|
||||
|
@ -61,36 +64,15 @@ class Section(NumberedModel):
|
|||
return self.title
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
verbose_name = _('section')
|
||||
verbose_name_plural = _('sections')
|
||||
ordering = ['position']
|
||||
#app_label = 'cms'
|
||||
|
||||
class SubSection(NumberedModel):
|
||||
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 Section(BaseSection):
|
||||
class Meta:
|
||||
verbose_name = _('subsection')
|
||||
verbose_name_plural = _('subsections')
|
||||
ordering = ['position']
|
||||
swappable = swapper.swappable_setting('cms', 'Section')
|
||||
|
||||
class Config(models.Model):
|
||||
TYPES = [
|
||||
|
|
|
@ -188,8 +188,6 @@ div.edit a, div.edit button, a.edit{
|
|||
display: inline;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
&:before {
|
||||
content: '[ ';
|
||||
|
|
|
@ -140,9 +140,7 @@ div.edit a, div.edit button, a.edit {
|
|||
border: none;
|
||||
display: inline;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
cursor: pointer; }
|
||||
div.edit a:before, div.edit button:before, a.edit:before {
|
||||
content: '[ '; }
|
||||
div.edit a:after, div.edit button:after, a.edit:after {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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 == 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 %}
|
||||
{% if user.is_staff %}
|
||||
<li><a class="edit" href="{% url 'cms:createpage' %}">+ {% trans 'new page' %}</a></li>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
{% block content %}
|
||||
{% for section in sections %}
|
||||
<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>
|
||||
{% endfor %}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{% extends 'cms/sections/base.html' %}
|
|
@ -1,5 +1,5 @@
|
|||
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'
|
||||
|
||||
|
@ -9,7 +9,6 @@ urlpatterns = [
|
|||
path('updatesection/<int:pk>/', UpdateSection.as_view(), name='updatesection'),
|
||||
path('createpage/', CreatePage.as_view(), name='createpage'),
|
||||
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!
|
||||
path('', PageView.as_view(), name='page'),
|
||||
|
|
51
cms/views.py
51
cms/views.py
|
@ -4,10 +4,13 @@ from django.shortcuts import redirect
|
|||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
from django.views.generic import DetailView, UpdateView, CreateView
|
||||
|
||||
from .models import Page, Section, SubSection
|
||||
from .forms import PageForm, SectionFormSet, SectionForm, SubSectionFormSet, SubSectionForm
|
||||
from .models import Page
|
||||
from .forms import PageForm, SectionForm
|
||||
from .utils import get_config
|
||||
|
||||
import swapper
|
||||
Section = swapper.load_model('cms', 'Section')
|
||||
|
||||
class StaffRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return self.request.user.is_staff
|
||||
|
@ -68,59 +71,17 @@ class CreateSection(StaffRequiredMixin, MenuMixin, CreateView):
|
|||
form.save()
|
||||
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):
|
||||
template_name = 'cms/edit.html'
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
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):
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
formset.save()
|
||||
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):
|
||||
model = Page
|
||||
form_class = PageForm
|
||||
formset_class = SectionFormSet
|
||||
|
||||
def get_formset_form_url(self, page):
|
||||
return reverse('cms:createsection', args=[page.pk])
|
||||
|
||||
class UpdateSection(BaseUpdateView):
|
||||
model = Section
|
||||
form_class = SectionForm
|
||||
formset_class = SubSectionFormSet
|
||||
|
||||
def get_formset_form_url(self, page):
|
||||
return reverse('cms:createsubsection', args=[page.pk])
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'app.apps.Config'
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
from django.apps import AppConfig
|
||||
class Config(AppConfig):
|
||||
name = 'app'
|
||||
verbose_name = 'app'
|
|
@ -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',),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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"
|
||||
}
|
|
@ -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 %}
|
|
@ -5,7 +5,7 @@ try:
|
|||
except ImportError:
|
||||
DEBUG = True
|
||||
|
||||
PROJECT_NAME = INSERT_PROJECT_NAME_HERE
|
||||
PROJECT_NAME = 'example'
|
||||
KEYFILE = f'/tmp/{PROJECT_NAME}.secret'
|
||||
ADMINS = [('JJ Vens', 'jj@rtts.eu')]
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
@ -22,6 +22,7 @@ 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):
|
||||
with open(file) as f:
|
||||
|
@ -36,7 +37,8 @@ except IOError:
|
|||
write(KEYFILE, SECRET_KEY)
|
||||
|
||||
SECTION_TYPES = [
|
||||
('normal', 'Normaal'),
|
||||
('TextSection', 'Tekst'),
|
||||
('ImageSection', 'Afbeelding'),
|
||||
]
|
||||
|
||||
SECTION_COLORS = [
|
||||
|
@ -63,8 +65,7 @@ CKEDITOR_CONFIGS = {
|
|||
}
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'simplesass',
|
||||
PROJECT_NAME,
|
||||
'app',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
|
@ -72,7 +73,9 @@ INSTALLED_APPS = [
|
|||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'cms',
|
||||
'simplesass',
|
||||
'ckeditor',
|
||||
'polymorphic',
|
||||
'embed_video',
|
||||
'easy_thumbnails',
|
||||
'django_extensions',
|
||||
|
|
|
@ -3,6 +3,8 @@ Django
|
|||
django-ckeditor
|
||||
django-extensions
|
||||
django-embed-video
|
||||
django-polymorphic
|
||||
easy-thumbnails
|
||||
psycopg2
|
||||
libsass
|
||||
swapper
|
||||
|
|
2
setup.py
2
setup.py
|
@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|||
|
||||
setup(
|
||||
name = 'django-simplecms',
|
||||
version = '1.0.2',
|
||||
version = '2.0.0',
|
||||
url = 'https://github.com/rtts/django-simplecms',
|
||||
author = 'Jaap Joris Vens',
|
||||
author_email = 'jj@rtts.eu',
|
||||
|
|
Ładowanie…
Reference in New Issue