The dependency on swapper has been replaced with an incredibly simply

"registry". Client projects register their models and views during import
time with a decorator. The cms views use the registered classes to generate
pages and forms.

Furthermore, the example application now combines the app and the project in
one, inspired by this line in the Django documentation:

    There’s no restriction that a project package can’t also be considered
    an application and have models, etc.
main
Jaap Joris Vens 2020-03-22 12:46:10 +01:00
rodzic 98b1a61af1
commit 0e221ccf33
32 zmienionych plików z 123 dodań i 243 usunięć

Wyświetl plik

@ -1,4 +1 @@
from .decorators import register
from .cms import SectionView, SectionFormView
default_app_config = 'cms.apps.CmsConfig' default_app_config = 'cms.apps.CmsConfig'

Wyświetl plik

@ -1,25 +0,0 @@
from django.views.generic import edit
from django.http import HttpResponseRedirect
class SectionView:
'''Generic section view'''
template_name = 'cms/sections/section.html'
def __init__(self, request):
'''Initialize request attribute'''
self.request = request
def get_context_data(self, **kwargs):
'''Override this to customize a section's context'''
return kwargs
class SectionFormView(edit.FormMixin, SectionView):
'''Generic section with associated form'''
def post(self, request):
'''Process form'''
form = self.get_form()
if form.is_valid():
form.save(request)
return HttpResponseRedirect(self.get_success_url())
return form

Wyświetl plik

@ -1,25 +1,17 @@
def register(verbose_name): from cms import registry
import swapper
Section = swapper.load_model('cms', 'Section')
'''Decorator to register a specific section type''' def page_model(cls):
def wrapper(view): '''Decorator to register the Page model'''
Section._cms_views[view.__name__.lower()] = view registry.page_class = cls
Section.TYPES.append((view.__name__.lower(), verbose_name)) return cls
return view
return wrapper
# def register_model(verbose_name): def section_model(cls):
# '''Decorator to register a section subclass''' '''Decorator to register the Section model'''
# def wrapper(model): registry.section_class = cls
# parent_model = model.__bases__[-1] return cls
# parent_model.TYPES.append((model.__name__.lower(), verbose_name))
# return model
# return wrapper
# def register_view(section_class): def section_view(cls):
# '''Decorator to connect a section model to a view class''' '''Decorator to register a view for a specific section'''
# def wrapper(model): registry.views_per_type[cls.__name__.lower()] = cls
# section_class.view_class = model registry.section_class.TYPES.append((cls.__name__.lower(), cls.verbose_name))
# return model return cls
# return wrapper

Wyświetl plik

@ -1,4 +1,3 @@
import swapper
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.db.models import Prefetch from django.db.models import Prefetch
@ -6,8 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
Page = swapper.load_model('cms', 'Page') from . import registry
Section = swapper.load_model('cms', 'Section')
class PageForm(forms.ModelForm): class PageForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -15,8 +13,8 @@ class PageForm(forms.ModelForm):
self.label_suffix = '' self.label_suffix = ''
extra = 1 if self.instance.pk else 2 extra = 1 if self.instance.pk else 2
self.formsets = [forms.inlineformset_factory( self.formsets = [forms.inlineformset_factory(
parent_model = Page, parent_model = registry.page_class,
model = Section, model = registry.section_class,
form = SectionForm, form = SectionForm,
extra=extra, extra=extra,
)( )(
@ -50,7 +48,7 @@ class PageForm(forms.ModelForm):
return page return page
class Meta: class Meta:
model = Page model = registry.page_class
fields = '__all__' fields = '__all__'
class SectionForm(forms.ModelForm): class SectionForm(forms.ModelForm):
@ -73,7 +71,7 @@ class SectionForm(forms.ModelForm):
for field in self.instance._meta.get_fields(): for field in self.instance._meta.get_fields():
if field.one_to_many: if field.one_to_many:
formset = forms.inlineformset_factory( formset = forms.inlineformset_factory(
parent_model=Section, parent_model=registry.section_class,
model=field.related_model, model=field.related_model,
fields='__all__', fields='__all__',
extra=extra, extra=extra,
@ -116,7 +114,7 @@ class SectionForm(forms.ModelForm):
return section return section
class Meta: class Meta:
model = Section model = registry.section_class
exclude = ['page'] exclude = ['page']
class ContactForm(forms.Form): class ContactForm(forms.Form):

Wyświetl plik

@ -1,61 +0,0 @@
# Generated by Django 3.0.2 on 2020-02-16 14:27
import cms.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import embed_video.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.CMS_PAGE_MODEL),
('contenttypes', '0002_remove_content_type_name'),
]
operations = [
migrations.CreateModel(
name='Page',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('number', models.PositiveIntegerField(blank=True, verbose_name='number')),
('title', cms.models.VarCharField(verbose_name='page')),
('slug', models.SlugField(blank=True, unique=True, verbose_name='slug')),
('menu', models.BooleanField(default=True, verbose_name='visible in menu')),
],
options={
'verbose_name': 'Page',
'verbose_name_plural': 'Pages',
'ordering': ['number'],
'abstract': False,
'swappable': 'CMS_PAGE_MODEL',
},
bases=(cms.models.Numbered, models.Model),
),
migrations.CreateModel(
name='Section',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', cms.models.VarCharField(verbose_name='type')),
('number', models.PositiveIntegerField(blank=True, verbose_name='number')),
('title', cms.models.VarCharField(verbose_name='section')),
('content', models.TextField(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')),
('href', cms.models.VarCharField(blank=True, verbose_name='link')),
('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')),
],
options={
'verbose_name': 'section',
'verbose_name_plural': 'sections',
'ordering': ['number'],
'abstract': False,
'swappable': 'CMS_SECTION_MODEL',
},
bases=(cms.models.Numbered, models.Model),
),
]

Wyświetl plik

@ -1,17 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-21 10:23
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('cms', '0002_initial_homepage'),
]
operations = [
migrations.RemoveField(
model_name='section',
name='polymorphic_ctype',
),
]

Wyświetl plik

@ -1,5 +1,3 @@
import swapper
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils.text import slugify from django.utils.text import slugify
@ -89,16 +87,10 @@ class BasePage(Numbered, models.Model):
class BaseSection(Numbered, models.Model): class BaseSection(Numbered, models.Model):
'''Abstract base model for sections''' '''Abstract base model for sections'''
# These will be populated by @register
TYPES = [] TYPES = []
_cms_views = {}
page = models.ForeignKey(swapper.get_model_name('cms', 'Page'), verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
title = VarCharField(_('section')) title = VarCharField(_('section'))
type = VarCharField(_('type')) type = VarCharField(_('type'))
number = models.PositiveIntegerField(_('number'), blank=True) number = models.PositiveIntegerField(_('number'), blank=True)
content = models.TextField(_('content'), blank=True) content = models.TextField(_('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'))
@ -118,33 +110,8 @@ class BaseSection(Numbered, models.Model):
else: else:
return self.title return self.title
def get_view(self, request):
'''Try to instantiate the registered view for this section'''
try:
return self.__class__._cms_views[self.type](request)
except:
raise ImproperlyConfigured(
f'No view registered for sections of type {self.type}!')
@classmethod
def get_fields_per_type(cls):
fields_per_type = {}
for name, view in cls._cms_views.items():
fields_per_type[name] = ['type', 'number'] + view.fields
return fields_per_type
class Meta: class Meta:
abstract = True abstract = True
verbose_name = _('section') verbose_name = _('section')
verbose_name_plural = _('sections') verbose_name_plural = _('sections')
ordering = ['number'] ordering = ['number']
class Page(BasePage):
'''Swappable page model'''
class Meta(BasePage.Meta):
swappable = swapper.swappable_setting('cms', 'Page')
class Section(BaseSection):
'''Swappable section model'''
class Meta(BaseSection.Meta):
swappable = swapper.swappable_setting('cms', 'Section')

13
cms/registry.py 100644
Wyświetl plik

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

Wyświetl plik

@ -5,6 +5,8 @@ from django.shortcuts import reverse
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 cms import registry
MARKDOWN_EXTENSIONS = ['extra', 'smarty'] MARKDOWN_EXTENSIONS = ['extra', 'smarty']
register = template.Library() register = template.Library()
@ -51,7 +53,7 @@ class IncludeSectionNode(template.Node):
csrf_token = self.csrf_token.resolve(context) csrf_token = self.csrf_token.resolve(context)
request = self.request.resolve(context) request = self.request.resolve(context)
perms = self.perms.resolve(context) perms = self.perms.resolve(context)
view = section.get_view(request) view = registry.get_view(section, request)
section_context = view.get_context_data( section_context = view.get_context_data(
csrf_token=csrf_token, csrf_token=csrf_token,
section=section, section=section,

Wyświetl plik

@ -1,19 +1,39 @@
import json import json
import swapper
from django.shortcuts import redirect from django.shortcuts import redirect
from django.views.generic import base, detail, edit from django.views.generic import base, detail, edit
from django.contrib.auth.mixins import UserPassesTestMixin from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseBadRequest from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
from . import registry
from .forms import PageForm, SectionForm from .forms import PageForm, SectionForm
Page = swapper.load_model('cms', 'Page') class SectionView:
Section = swapper.load_model('cms', 'Section') '''Generic section view'''
template_name = 'cms/sections/section.html'
def __init__(self, request):
'''Initialize request attribute'''
self.request = request
def get_context_data(self, **kwargs):
'''Override this to customize a section's context'''
return kwargs
class SectionFormView(edit.FormMixin, SectionView):
'''Generic section with associated form'''
def post(self, request):
'''Process form'''
form = self.get_form()
if form.is_valid():
form.save(request)
return HttpResponseRedirect(self.get_success_url())
return form
class PageView(detail.DetailView): class PageView(detail.DetailView):
'''View of a page with heterogeneous sections''' '''View of a page with heterogeneous sections'''
model = Page model = registry.page_class
template_name = 'cms/page.html' template_name = 'cms/page.html'
def setup(self, *args, slug='', **kwargs): def setup(self, *args, slug='', **kwargs):
@ -25,8 +45,13 @@ class PageView(detail.DetailView):
try: try:
page = self.object = self.get_object() page = self.object = self.get_object()
except Http404: except Http404:
if self.request.user.has_perm('cms_page_create'): if self.kwargs['slug'] == '':
page = registry.page_class(title='Homepage', slug='')
page.save()
self.object = page
elif self.request.user.has_perm('cms_page_create'):
return redirect('cms:updatepage', self.kwargs['slug']) return redirect('cms:updatepage', self.kwargs['slug'])
else:
raise raise
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
sections = page.sections.all() sections = page.sections.all()
@ -48,7 +73,7 @@ class PageView(detail.DetailView):
sections = page.sections.all() sections = page.sections.all()
for section in sections: for section in sections:
if section.pk == pk: if section.pk == pk:
view = section.get_view(request) view = registry.get_view(section, request)
result = view.post(request) result = view.post(request)
if isinstance(result, HttpResponse): if isinstance(result, HttpResponse):
return result return result
@ -62,7 +87,7 @@ class PageView(detail.DetailView):
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 = registry.page_class.objects.filter(menu=True)
context.update({ context.update({
'pages': pages, 'pages': pages,
}) })
@ -70,7 +95,7 @@ class PageView(detail.DetailView):
class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View): class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View):
'''Base view with nested forms for editing the page and all its sections''' '''Base view with nested forms for editing the page and all its sections'''
model = Page model = registry.page_class
form_class = PageForm form_class = PageForm
template_name = 'cms/edit.html' template_name = 'cms/edit.html'
@ -88,7 +113,7 @@ class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMi
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
'''Populate the fields_per_type dict for use in javascript''' '''Populate the fields_per_type dict for use in javascript'''
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['fields_per_type'] = json.dumps(Section.get_fields_per_type()) context['fields_per_type'] = json.dumps(registry.get_fields_per_type())
return context return context
def get_object(self): def get_object(self):
@ -118,13 +143,13 @@ class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMi
class CreatePage(EditPage): class CreatePage(EditPage):
'''View for creating new pages''' '''View for creating new pages'''
def get_object(self): def get_object(self):
return Page() return registry.page_class()
class UpdatePage(EditPage): class UpdatePage(EditPage):
'''View for editing existing pages''' '''View for editing existing pages'''
class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View): class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View):
model = Section model = registry.section_class
form_class = SectionForm form_class = SectionForm
template_name = 'cms/edit.html' template_name = 'cms/edit.html'
@ -140,20 +165,20 @@ class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateRespons
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['fields_per_type'] = json.dumps(Section.get_fields_per_type()) context['fields_per_type'] = json.dumps(registry.get_fields_per_type())
return context return context
def get_object(self, queryset=None): def get_object(self, queryset=None):
try: try:
self.page = Page.objects.get(slug=self.kwargs['slug']) self.page = registry.page_class.objects.get(slug=self.kwargs['slug'])
except Page.DoesNotExist: except registry.page_class.DoesNotExist:
raise Http404() raise Http404()
return self.get_section() return self.get_section()
def get_section(self): def get_section(self):
try: try:
section = self.page.sections.get(number=self.kwargs['number']) section = self.page.sections.get(number=self.kwargs['number'])
except Section.DoesNotExist: except self.page.sections.DoesNotExist:
raise Http404() raise Http404()
return section return section
@ -177,7 +202,7 @@ class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateRespons
class CreateSection(EditSection): class CreateSection(EditSection):
def get_section(self): def get_section(self):
return Section(page=self.page) return registry.section_class(page=self.page)
class UpdateSection(EditSection): class UpdateSection(EditSection):
pass pass

Wyświetl plik

@ -1,26 +0,0 @@
# Generated by Django 3.0.2 on 2020-03-21 16:58
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('app', '0001_initial'),
]
operations = [
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=settings.CMS_SECTION_MODEL)),
],
options={
'ordering': ['pk'],
},
),
]

Wyświetl plik

@ -1,24 +1,29 @@
import cms from cms.views import SectionView, SectionFormView
from cms.decorators import section_view
from cms.forms import ContactForm from cms.forms import ContactForm
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@cms.register(_('Text')) @section_view
class Text(cms.SectionView): class Text(SectionView):
verbose_name = _('Text')
fields = ['title', 'content'] fields = ['title', 'content']
template_name = 'app/sections/text.html' template_name = 'app/sections/text.html'
@cms.register(_('Images')) @section_view
class Images(cms.SectionView): class Images(SectionView):
verbose_name = _('Images')
fields = ['title', 'images'] fields = ['title', 'images']
template_name = 'app/sections/images.html' template_name = 'app/sections/images.html'
@cms.register(_('Video')) @section_view
class Video(cms.SectionView): class Video(SectionView):
verbose_name = _('Video')
fields = ['title', 'video'] fields = ['title', 'video']
template_name = 'app/sections/video.html' template_name = 'app/sections/video.html'
@cms.register(_('Contact')) @section_view
class Contact(cms.SectionFormView): class Contact(SectionFormView):
verbose_name = _('Contact')
fields = ['title'] fields = ['title']
form_class = ContactForm form_class = ContactForm
success_url = '/thanks/' success_url = '/thanks/'

Wyświetl plik

@ -1,7 +1,6 @@
# Generated by Django 3.0.2 on 2020-03-21 16:44 # Generated by Django 3.0.2 on 2020-03-22 11:11
import cms.models 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
@ -32,6 +31,16 @@ class Migration(migrations.Migration):
}, },
bases=(cms.models.Numbered, models.Model), 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( migrations.CreateModel(
name='Section', name='Section',
fields=[ fields=[
@ -43,7 +52,7 @@ class Migration(migrations.Migration):
('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')),
('href', cms.models.VarCharField(blank=True, verbose_name='link')), ('href', cms.models.VarCharField(blank=True, verbose_name='link')),
('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to=settings.CMS_PAGE_MODEL, verbose_name='page')), ('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to='example.Page', verbose_name='page')),
], ],
options={ options={
'verbose_name': 'section', 'verbose_name': 'section',

Wyświetl plik

@ -1,21 +1,25 @@
from django.db import models from django.db import models
from cms.models import BasePage, BaseSection
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from cms.models import BasePage, BaseSection
from cms.decorators import page_model, section_model
@page_model
class Page(BasePage): class Page(BasePage):
'''Add custom fields here. Already existing fields: title, slug, '''Add custom fields here. Already existing fields: title, slug,
number, menu number, menu
''' '''
@section_model
class Section(BaseSection): class Section(BaseSection):
'''Add custom fields here. Already existing fields: title, type, '''Add custom fields here. Already existing fields: title, type,
number, content, image, video, href number, content, image, video, href
''' '''
page = models.ForeignKey(Page, verbose_name=_('page'), related_name='sections', on_delete=models.PROTECT)
class SectionImage(models.Model): 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')) image = models.ImageField(_('Image'))
class Meta: class Meta:

Wyświetl plik

@ -1,19 +1,13 @@
import os, random, string import os, random, string
try:
import uwsgi
DEBUG = False
except ImportError:
DEBUG = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
PROJECT_NAME = 'example' PROJECT_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
KEYFILE = f'/tmp/{PROJECT_NAME}.secret' KEYFILE = f'/tmp/{PROJECT_NAME}.secret'
ADMINS = [('JJ Vens', 'jj@rtts.eu')] ADMINS = [('JJ Vens', 'jj@rtts.eu')]
DEFAULT_FROM_EMAIL = 'noreply@rtts.eu' DEFAULT_FROM_EMAIL = 'noreply@rtts.eu'
DEFAULT_TO_EMAIL = 'jj@rtts.eu' DEFAULT_TO_EMAIL = 'jj@rtts.eu'
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
ROOT_URLCONF = 'project.urls' ROOT_URLCONF = PROJECT_NAME + '.urls'
WSGI_APPLICATION = 'project.wsgi.application' WSGI_APPLICATION = PROJECT_NAME + '.wsgi.application'
LANGUAGE_CODE = 'nl' LANGUAGE_CODE = 'nl'
TIME_ZONE = 'Europe/Amsterdam' TIME_ZONE = 'Europe/Amsterdam'
USE_I18N = True USE_I18N = True
@ -24,8 +18,13 @@ 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 = '/'
CMS_SECTION_MODEL = 'app.Section'
CMS_PAGE_MODEL = 'app.Page' try:
import uwsgi
DEBUG = False
except ImportError:
DEBUG = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
def read(file): def read(file):
with open(file) as f: with open(file) as f:
@ -40,7 +39,7 @@ except IOError:
write(KEYFILE, SECRET_KEY) write(KEYFILE, SECRET_KEY)
INSTALLED_APPS = [ INSTALLED_APPS = [
'app', PROJECT_NAME,
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',

Wyświetl plik

@ -3,7 +3,7 @@ import os
import sys import sys
if __name__ == '__main__': if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings')
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError as exc:

Wyświetl plik

@ -3,7 +3,7 @@ from setuptools import setup, find_packages
setup( setup(
name = 'django-simplecms', name = 'django-simplecms',
version = '2.3.1', version = '3.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',
@ -15,11 +15,9 @@ setup(
'django', 'django',
'django-extensions', 'django-extensions',
'django-embed-video', 'django-embed-video',
'django-polymorphic',
'easy-thumbnails', 'easy-thumbnails',
'psycopg2', 'psycopg2',
'markdown', 'markdown',
'libsass', 'libsass',
'swapper',
], ],
) )