diff --git a/README.md b/README.md
index 3dd465c..6757cd2 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,93 @@
*A super simple but very extensible content management system for
Django websites.*
-This project provides the basic building blocks of *Pages* and
-*Sections* and all the views needed to display and edit them.
+SimpleCMS provides the reusable Django app `cms` which contains
+everything you need to create websites that can be easily edited by
+end users.
+
+## How does it work?
+
+Contrary to 'regular' Django websites, SimpleCMS allows you to write a
+view for each *section*, rather than for each *page* on your website.
+On which pages these sections appear, and in which order, is left to
+the content editor rather than the programmer. After authenticating,
+the editor can use the {page,section}{create,update} forms to fill the
+website with various types of content.
+
+Here's an example `views.py` of an app using SimpleCMS:
+
+ from cms.views import SectionView
+ from cms.decorators import section_view
+
+ @section_view
+ class HelloWorld(SectionView):
+ verbose_name = 'Hello world section'
+ fields = ['content']
+ template_name = 'hello.html'
+
+ def get_context_data(self, **kwargs):
+ context = super()get_context_data(**kwargs)
+ context['message'] = 'Hello World!'
+
+And here is the contents of `hello.html`:
+
+
+
{{message}}
+ {{section.content}}
+
+
+Everytime a section needs to be rendered, your section view will be
+called by SimpleCMS and return a response which will get inserted into
+the final rendered page.
+
+## The "Edit" Interface
+
+Somewhat like the Django Admin site, SimpleCMS comes with its own
+editing environment, albeit much simpler and only suitable for editing
+pages and sections. After authenticating, the content editor can click
+the "edit" button on any page of the website to alter, add or
+rearrange sections.
+
+For each section, the section type can be selected from a dropdown
+menu. As you can see in `views.py` above, each section type comes with
+its own list of editable fields. Client-side javascript will hide/show
+the relevant fields based on the selected section type. All sections
+are stored in the same database table.
+
+## Batteries included!
+
+SimpleCMS has been specifically crafted to fit my own personal needs
+when building websites for customers. Therefore it includes a variety
+of useful template tags, default *Page* and *Section* models, and all
+the other boilerplate code needed for new projects.
+
+One notable inclusion is the `eval` template tag. It will pass its
+argument first through Django's templating system and then through
+Markdown, making for instance the following possible. (Disclaimer: use
+with caution!)
+
+ Welcome to **{% now 'Y' %}!**
+
+Another useful feature is the automatic compilation of `SCSS` files to
+`CSS` files using a custom middleware.
## Installation
Use the provided helper command `simplecms` to quickly setup a new
project:
- pip install https://github.com/rtts/django-simplecms.git
- simplecms mysite
+ $ pip install https://github.com/rtts/django-simplecms.git
+ $ simplecms mysite
+
+After the project files have been created, initialize the database and
+create a superuser:
+
+ $ cd mysite
+ $ sudo su postgres -c "createuser mysite; createdb -O mysite mysite"
+ $ ./manage.py migrate
+ $ ./manage.py createsuperuser
+
+Finally, run the development server and visit
+http://localhost:8000/login/ in your browser to log in!
+
+ $ ./manage.py runserver
diff --git a/bin/simplecms b/bin/simplecms
deleted file mode 100755
index 159fb27..0000000
--- a/bin/simplecms
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash -e
-
-test -z $1 && echo "Please provide a project name!" && exit 1
-
-mkdir -p $1 && cd $1
-pip3 freeze > requirements.txt
-example_dir=$(python3 -c 'import os,example;print(os.path.dirname(example.__file__))')
-cp -r $example_dir/{project,app,manage.py} .
-sed -i s/example/$1/ project/settings.py
-
-# Assume the user has sudo access to postgres
-sudo su postgres -c "createuser $1; createdb -O $1 $1" || true
-
-cat << EOF > .gitignore
-*.pyc
-__pycache__/
-EOF
-
-./manage.py makemigrations app
-./manage.py migrate
-./manage.py createsuperuser
-./manage.py runserver --nostatic
diff --git a/cms/apps.py b/cms/apps.py
index 6807913..a7614d9 100644
--- a/cms/apps.py
+++ b/cms/apps.py
@@ -7,4 +7,4 @@ class CmsConfig(AppConfig):
verbose_name = _('Content Management System')
def ready(self):
- autodiscover_modules('cms')
+ autodiscover_modules('views')
diff --git a/cms/bin/simplecms b/cms/bin/simplecms
new file mode 100755
index 0000000..ed70e3b
--- /dev/null
+++ b/cms/bin/simplecms
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+test -z $1 && echo "Please provide a project name!" && exit 1
+mkdir "$1"
+cd "$1"
+pip3 freeze > requirements.txt
+example_dir=$(python3 -c 'import os,example;print(os.path.dirname(example.__file__))')
+cp -r "$example_dir" "$1"
+cp "$example_dir"/../manage.py .
+sed -i "s/example/$1/" manage.py
+cat << EOF > .gitignore
+*.pyc
+__pycache__/
+EOF
+
+cat <
{% trans 'Please correct the error(s) below and save again' %}
+ {{form.errors}}
{% endif %}
@@ -75,8 +76,7 @@
function resizeTextareas() {
let tx = document.getElementsByTagName('textarea');
for (let i = 0; i < tx.length; i++) {
- tx[i].setAttribute('style', 'height:0;overflow-y:hidden;');
- tx[i].style.height = (tx[i].scrollHeight) + 'px';
+ tx[i].style.height = (tx[i].scrollHeight) + 1 + 'px';
tx[i].addEventListener('input', function() {
this.style.height = (this.scrollHeight) + 1 + 'px'; // why the 1???
});
diff --git a/example/migrations/0001_initial.py b/example/migrations/0001_initial.py
index 1afc47d..9428392 100644
--- a/example/migrations/0001_initial.py
+++ b/example/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.0.2 on 2020-03-22 11:11
+# Generated by Django 3.0.2 on 2020-03-22 15:45
import cms.models
from django.db import migrations, models
@@ -31,16 +31,6 @@ class Migration(migrations.Migration):
},
bases=(cms.models.Numbered, models.Model),
),
- migrations.CreateModel(
- name='SectionImage',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('image', models.ImageField(upload_to='', verbose_name='Image')),
- ],
- options={
- 'ordering': ['pk'],
- },
- ),
migrations.CreateModel(
name='Section',
fields=[
@@ -62,4 +52,15 @@ class Migration(migrations.Migration):
},
bases=(cms.models.Numbered, models.Model),
),
+ migrations.CreateModel(
+ name='SectionImage',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('image', models.ImageField(upload_to='', verbose_name='Image')),
+ ('section', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='example.Section')),
+ ],
+ options={
+ 'ordering': ['pk'],
+ },
+ ),
]
diff --git a/example/migrations/0002_initial_homepage.bak b/example/migrations/0002_initial_homepage.bak
deleted file mode 100644
index 1263099..0000000
--- a/example/migrations/0002_initial_homepage.bak
+++ /dev/null
@@ -1,16 +0,0 @@
-import swapper
-from django.db import migrations
-Page = swapper.load_model('cms', 'Page')
-
-def add_homepage(apps, schema_editor):
- if not Page.objects.exists():
- Page(slug='', title='Homepage', number=1).save()
-
-class Migration(migrations.Migration):
- dependencies = [
- ('cms', '0001_initial'),
- ]
-
- operations = [
- migrations.RunPython(add_homepage, migrations.RunPython.noop),
- ]
diff --git a/example/models.py b/example/models.py
index d3f8edf..bee5108 100644
--- a/example/models.py
+++ b/example/models.py
@@ -19,7 +19,7 @@ class Section(BaseSection):
page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
class SectionImage(models.Model):
- #section = models.ForeignKey(Section, related_name='images', on_delete=models.CASCADE)
+ section = models.ForeignKey(Section, related_name='images', on_delete=models.CASCADE)
image = models.ImageField(_('Image'))
class Meta:
diff --git a/example/settings.py b/example/settings.py
index 75ead46..50ceed2 100644
--- a/example/settings.py
+++ b/example/settings.py
@@ -26,17 +26,13 @@ except ImportError:
DEBUG = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
-def read(file):
- with open(file) as f:
- return f.read()
-def write(file, content):
- with open(file, 'w') as f:
- f.write(content)
try:
- SECRET_KEY = read(KEYFILE)
+ with open(KEYFILE) as f:
+ SECRET_KEY = f.read()
except IOError:
SECRET_KEY = ''.join(random.choice(string.printable) for x in range(50))
- write(KEYFILE, SECRET_KEY)
+ with open(KEYFILE, 'w') as f:
+ f.write(SECRET_KEY)
INSTALLED_APPS = [
PROJECT_NAME,
@@ -45,12 +41,13 @@ INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
- 'django.contrib.staticfiles',
'cms',
'embed_video',
'easy_thumbnails',
'django_extensions',
]
+if not DEBUG:
+ INSTALLED_APPS += ['django.contrib.staticfiles']
MIDDLEWARE = [
'cms.middleware.SassMiddleware',
diff --git a/example/static/app/hamburgers.css b/example/static/hamburgers.css
similarity index 100%
rename from example/static/app/hamburgers.css
rename to example/static/hamburgers.css
diff --git a/example/static/app/main1.scss b/example/static/main1.scss
similarity index 100%
rename from example/static/app/main1.scss
rename to example/static/main1.scss
diff --git a/example/static/app/main1.scss.css b/example/static/main1.scss.css
similarity index 100%
rename from example/static/app/main1.scss.css
rename to example/static/main1.scss.css
diff --git a/example/static/app/main1.scss.css.map b/example/static/main1.scss.css.map
similarity index 100%
rename from example/static/app/main1.scss.css.map
rename to example/static/main1.scss.css.map
diff --git a/example/templates/base.html b/example/templates/base.html
index db51408..35770c1 100644
--- a/example/templates/base.html
+++ b/example/templates/base.html
@@ -4,8 +4,8 @@
{% block title %}Awesome Website{% endblock %}
{% block extrahead %}
-
-
+
+
{% endblock %}
{% block header %}
diff --git a/example/templates/app/sections/contact.html b/example/templates/contact.html
similarity index 100%
rename from example/templates/app/sections/contact.html
rename to example/templates/contact.html
diff --git a/example/templates/app/sections/images.html b/example/templates/images.html
similarity index 100%
rename from example/templates/app/sections/images.html
rename to example/templates/images.html
diff --git a/example/templates/app/sections/text.html b/example/templates/text.html
similarity index 100%
rename from example/templates/app/sections/text.html
rename to example/templates/text.html
diff --git a/example/templates/app/sections/video.html b/example/templates/video.html
similarity index 100%
rename from example/templates/app/sections/video.html
rename to example/templates/video.html
diff --git a/example/cms.py b/example/views.py
similarity index 59%
rename from example/cms.py
rename to example/views.py
index c388929..e891d71 100644
--- a/example/cms.py
+++ b/example/views.py
@@ -1,30 +1,30 @@
+from django.utils.translation import gettext_lazy as _
from cms.views import SectionView, SectionFormView
from cms.decorators import section_view
from cms.forms import ContactForm
-from django.utils.translation import gettext_lazy as _
@section_view
class Text(SectionView):
verbose_name = _('Text')
- fields = ['title', 'content']
- template_name = 'app/sections/text.html'
+ fields = ['content']
+ template_name = 'text.html'
@section_view
class Images(SectionView):
- verbose_name = _('Images')
- fields = ['title', 'images']
- template_name = 'app/sections/images.html'
+ verbose_name = _('Image(s)')
+ fields = ['images']
+ template_name = 'images.html'
@section_view
class Video(SectionView):
verbose_name = _('Video')
- fields = ['title', 'video']
- template_name = 'app/sections/video.html'
+ fields = ['video']
+ template_name = 'video.html'
@section_view
class Contact(SectionFormView):
verbose_name = _('Contact')
- fields = ['title']
+ fields = []
form_class = ContactForm
success_url = '/thanks/'
- template_name = 'app/sections/contact.html'
+ template_name = 'contact.html'
diff --git a/setup.py b/setup.py
index edd1a48..751ba92 100755
--- a/setup.py
+++ b/setup.py
@@ -3,13 +3,13 @@ from setuptools import setup, find_packages
setup(
name = 'django-simplecms',
- version = '3.0.0',
+ version = '1.0.0',
url = 'https://github.com/rtts/django-simplecms',
author = 'Jaap Joris Vens',
author_email = 'jj@rtts.eu',
license = 'GPL3',
packages = find_packages(),
- scripts = ['bin/simplecms'],
+ scripts = ['cms/bin/simplecms'],
include_package_data = True,
install_requires = [
'django',