main
Jaap Joris Vens 2020-03-22 19:57:48 +01:00
rodzic 0e221ccf33
commit 2382fd47f0
27 zmienionych plików z 205 dodań i 126 usunięć

Wyświetl plik

@ -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`:
<section type="helloworld">
<h1>{{message}}</h1>
{{section.content}}
</section>
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

Wyświetl plik

@ -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

Wyświetl plik

@ -7,4 +7,4 @@ class CmsConfig(AppConfig):
verbose_name = _('Content Management System')
def ready(self):
autodiscover_modules('cms')
autodiscover_modules('views')

26
cms/bin/simplecms 100755
Wyświetl plik

@ -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 <<EOF
Successfully created project "$1"!
Things to do next:
- create a database
- ./manage.py migrate
- ./manage.py createsuperuser
- ./manage.py runserver --nostatic
EOF

Wyświetl plik

@ -12,6 +12,6 @@ def section_model(cls):
def section_view(cls):
'''Decorator to register a view for a specific section'''
registry.views_per_type[cls.__name__.lower()] = cls
registry.section_class.TYPES.append((cls.__name__.lower(), cls.verbose_name))
registry.view_per_type[cls.__name__.lower()] = cls
registry.section_types.append((cls.__name__.lower(), cls.verbose_name))
return cls

Wyświetl plik

@ -11,20 +11,18 @@ class PageForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.label_suffix = ''
extra = 1 if self.instance.pk else 2
self.formsets = [forms.inlineformset_factory(
parent_model = registry.page_class,
model = registry.section_class,
form = SectionForm,
extra=extra,
parent_model=registry.page_class,
model=registry.section_class,
form=SectionForm,
extra=1,
)(
data=self.data if self.is_bound else None,
files=self.files if self.is_bound else None,
instance=self.instance,
form_kwargs={'label_suffix': self.label_suffix},
)]
if not self.instance.pk:
self.formsets[0][0].empty_permitted = False
self.formsets[0][0].empty_permitted = True
def is_valid(self):
return super().is_valid() and self.formsets[0].is_valid()
@ -42,9 +40,6 @@ class PageForm(forms.ModelForm):
formset = self.formsets[0]
formset.instance = page
formset.save()
if page.slug and not page.sections.exists():
page.delete()
return None
return page
class Meta:
@ -58,12 +53,8 @@ class SectionForm(forms.ModelForm):
super().__init__(*args, **kwargs)
self.label_suffix = ''
self.fields['DELETE'] = forms.BooleanField(label=_('Delete'), required=False)
extra = 1 if self.instance.pk else 2
# Repopulate the 'choices' attribute of the type field from
# the child model.
self.fields['type'].choices = self._meta.model.TYPES
self.fields['type'].initial = self._meta.model.TYPES[0][0]
self.fields['type'].choices = registry.get_types()
self.fields['type'].initial = registry.get_types()[0][0]
# Populate the 'formsets' attribute if the Section was
# extendend with one_to_many fields
@ -74,7 +65,7 @@ class SectionForm(forms.ModelForm):
parent_model=registry.section_class,
model=field.related_model,
fields='__all__',
extra=extra,
extra=1,
)(
instance=self.instance,
data=self.data if self.is_bound else None,

Wyświetl plik

@ -1,27 +1,35 @@
import os
from django.conf import settings
from django.apps import apps
from sass import compile
from django.conf import settings
def locate(filename):
for path, dirs, files in os.walk(os.getcwd()):
for f in files:
if f == filename:
return os.path.join(path, filename)
class SassMiddleware:
'''Simple SASS middleware that intercepts requests for .css files and
tries to compile the corresponding SCSS file.
'''
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if settings.DEBUG and request.path.endswith('.css'):
_, staticdir, appname, css_file = request.path.split('/', maxsplit=3)
app_path = apps.get_app_config(appname).path
sass_file = css_file[:-4]
css_path = os.path.join(app_path, staticdir, appname, css_file)
sass_path = os.path.join(app_path, staticdir, appname, sass_file)
map_path = css_path + '.map'
if os.path.exists(sass_path):
css = compile(filename=sass_path, output_style='nested')
css, mapping = compile(filename=sass_path, source_map_filename=map_path)
with open(css_path, 'w') as f:
f.write(css)
with open(map_path, 'w') as f:
f.write(mapping)
css_file = request.path.rsplit('/',1)[1]
css_path = locate(css_file)
if css_path:
sass_path = css_path[:-4]
map_path = css_path + '.map'
if os.path.exists(sass_path):
css = compile(filename=sass_path, output_style='nested')
css, mapping = compile(filename=sass_path, source_map_filename=map_path)
with open(css_path, 'w') as f:
f.write(css)
with open(map_path, 'w') as f:
f.write(mapping)
response = self.get_response(request)
return response

Wyświetl plik

@ -1,13 +1,17 @@
views_per_type = {}
page_class = None
section_class = None
section_types = []
view_per_type = {}
def get_types():
return section_types
def get_view(section, request):
'''Instantiate the registered view of a section'''
return views_per_type[section.type](request)
return view_per_type[section.type](request)
def get_fields_per_type():
fields_per_type = {}
for name, view in views_per_type.items():
for name, view in view_per_type.items():
fields_per_type[name] = ['title', 'type', 'number'] + view.fields
return fields_per_type

Wyświetl plik

@ -46,7 +46,7 @@ form.cms {
background: $background;
border: 0.5px solid #ccc;
clear: both;
margin: 0.5em 0em;
margin: 0.25em 0em;
padding: 0.25em 0.5em;
padding-top: 0;
border-radius: 0.25em;
@ -60,7 +60,9 @@ form.cms {
}
div.formfield {
margin: 0.25em 0;
margin-top: 0.25em;
margin-bottom: 0.25em;
overflow: hidden;
clear: both;
box-sizing: border-box;
@ -68,6 +70,7 @@ form.cms {
width: 77%;
clear: none;
float: left;
margin-top: 0;
}
&.number {
width: 20%;
@ -108,6 +111,7 @@ form.cms {
}
input, select, textarea {
height: 32px;
background: $background;
color: black;
border: 0.5px solid #ccc;
@ -130,6 +134,7 @@ form.cms {
font-size: 1rem;
height: 15em;
line-height: 1.5;
overflow-y: hidden;
}
select {
padding-left: 3px;

Wyświetl plik

@ -34,7 +34,7 @@ form.cms {
background: #fff6;
border: 0.5px solid #ccc;
clear: both;
margin: 0.5em 0em;
margin: 0.25em 0em;
padding: 0.25em 0.5em;
padding-top: 0;
border-radius: 0.25em; }
@ -44,13 +44,16 @@ form.cms {
width: 50px;
cursor: pointer; }
form.cms div.formfield {
margin: 0.25em 0;
margin-top: 0.25em;
margin-bottom: 0.25em;
overflow: hidden;
clear: both;
box-sizing: border-box; }
form.cms div.formfield.type, form.cms div.formfield.number, form.cms div.formfield.slug {
width: 77%;
clear: none;
float: left; }
float: left;
margin-top: 0; }
form.cms div.formfield.number {
width: 20%;
float: right; }
@ -76,6 +79,7 @@ form.cms {
font-size: 12px !important;
font-weight: 400 !important; }
form.cms input, form.cms select, form.cms textarea {
height: 32px;
background: #fff6;
color: black;
border: 0.5px solid #ccc;
@ -95,7 +99,8 @@ form.cms {
form.cms textarea {
font-size: 1rem;
height: 15em;
line-height: 1.5; }
line-height: 1.5;
overflow-y: hidden; }
form.cms select {
padding-left: 3px; }
form.cms ul.errorlist {

Wyświetl plik

@ -5,5 +5,5 @@
"admin.scss"
],
"names": [],
"mappings": "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"
"mappings": "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"
}

Wyświetl plik

@ -11,6 +11,7 @@
{% if form.errors %}
<div class="global_error">
{% trans 'Please correct the error(s) below and save again' %}
{{form.errors}}
</div>
{% 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???
});

Wyświetl plik

@ -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'],
},
),
]

Wyświetl plik

@ -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),
]

Wyświetl plik

@ -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:

Wyświetl plik

@ -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',

Wyświetl plik

@ -4,8 +4,8 @@
{% block title %}Awesome Website{% endblock %}
{% block extrahead %}
<link rel="stylesheet" href="{% static 'app/hamburgers.css' %}">
<link rel="stylesheet" href="{% static 'app/main1.scss.css' %}">
<link rel="stylesheet" href="{% static 'hamburgers.css' %}">
<link rel="stylesheet" href="{% static 'main1.scss.css' %}">
{% endblock %}
{% block header %}

Wyświetl plik

@ -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'

Wyświetl plik

@ -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',