kopia lustrzana https://github.com/rtts/django-simplecms
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
rodzic
98b1a61af1
commit
0e221ccf33
|
@ -1,4 +1 @@
|
|||
from .decorators import register
|
||||
from .cms import SectionView, SectionFormView
|
||||
|
||||
default_app_config = 'cms.apps.CmsConfig'
|
||||
|
|
25
cms/cms.py
25
cms/cms.py
|
@ -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
|
|
@ -1,25 +1,17 @@
|
|||
def register(verbose_name):
|
||||
import swapper
|
||||
Section = swapper.load_model('cms', 'Section')
|
||||
from cms import registry
|
||||
|
||||
'''Decorator to register a specific section type'''
|
||||
def wrapper(view):
|
||||
Section._cms_views[view.__name__.lower()] = view
|
||||
Section.TYPES.append((view.__name__.lower(), verbose_name))
|
||||
return view
|
||||
return wrapper
|
||||
def page_model(cls):
|
||||
'''Decorator to register the Page model'''
|
||||
registry.page_class = cls
|
||||
return cls
|
||||
|
||||
# def register_model(verbose_name):
|
||||
# '''Decorator to register a section subclass'''
|
||||
# def wrapper(model):
|
||||
# parent_model = model.__bases__[-1]
|
||||
# parent_model.TYPES.append((model.__name__.lower(), verbose_name))
|
||||
# return model
|
||||
# return wrapper
|
||||
def section_model(cls):
|
||||
'''Decorator to register the Section model'''
|
||||
registry.section_class = cls
|
||||
return cls
|
||||
|
||||
# def register_view(section_class):
|
||||
# '''Decorator to connect a section model to a view class'''
|
||||
# def wrapper(model):
|
||||
# section_class.view_class = model
|
||||
# return model
|
||||
# return wrapper
|
||||
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))
|
||||
return cls
|
||||
|
|
14
cms/forms.py
14
cms/forms.py
|
@ -1,4 +1,3 @@
|
|||
import swapper
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
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.utils.translation import gettext_lazy as _
|
||||
|
||||
Page = swapper.load_model('cms', 'Page')
|
||||
Section = swapper.load_model('cms', 'Section')
|
||||
from . import registry
|
||||
|
||||
class PageForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -15,8 +13,8 @@ class PageForm(forms.ModelForm):
|
|||
self.label_suffix = ''
|
||||
extra = 1 if self.instance.pk else 2
|
||||
self.formsets = [forms.inlineformset_factory(
|
||||
parent_model = Page,
|
||||
model = Section,
|
||||
parent_model = registry.page_class,
|
||||
model = registry.section_class,
|
||||
form = SectionForm,
|
||||
extra=extra,
|
||||
)(
|
||||
|
@ -50,7 +48,7 @@ class PageForm(forms.ModelForm):
|
|||
return page
|
||||
|
||||
class Meta:
|
||||
model = Page
|
||||
model = registry.page_class
|
||||
fields = '__all__'
|
||||
|
||||
class SectionForm(forms.ModelForm):
|
||||
|
@ -73,7 +71,7 @@ class SectionForm(forms.ModelForm):
|
|||
for field in self.instance._meta.get_fields():
|
||||
if field.one_to_many:
|
||||
formset = forms.inlineformset_factory(
|
||||
parent_model=Section,
|
||||
parent_model=registry.section_class,
|
||||
model=field.related_model,
|
||||
fields='__all__',
|
||||
extra=extra,
|
||||
|
@ -116,7 +114,7 @@ class SectionForm(forms.ModelForm):
|
|||
return section
|
||||
|
||||
class Meta:
|
||||
model = Section
|
||||
model = registry.section_class
|
||||
exclude = ['page']
|
||||
|
||||
class ContactForm(forms.Form):
|
||||
|
|
|
@ -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),
|
||||
),
|
||||
]
|
|
@ -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',
|
||||
),
|
||||
]
|
|
@ -1,5 +1,3 @@
|
|||
import swapper
|
||||
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
|
@ -89,16 +87,10 @@ class BasePage(Numbered, models.Model):
|
|||
|
||||
class BaseSection(Numbered, models.Model):
|
||||
'''Abstract base model for sections'''
|
||||
|
||||
# These will be populated by @register
|
||||
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'))
|
||||
type = VarCharField(_('type'))
|
||||
number = models.PositiveIntegerField(_('number'), blank=True)
|
||||
|
||||
content = models.TextField(_('content'), blank=True)
|
||||
image = models.ImageField(_('image'), blank=True)
|
||||
video = EmbedVideoField(_('video'), blank=True, help_text=_('Paste a YouTube, Vimeo, or SoundCloud link'))
|
||||
|
@ -118,33 +110,8 @@ class BaseSection(Numbered, models.Model):
|
|||
else:
|
||||
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:
|
||||
abstract = True
|
||||
verbose_name = _('section')
|
||||
verbose_name_plural = _('sections')
|
||||
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')
|
||||
|
|
|
@ -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
|
|
@ -5,6 +5,8 @@ from django.shortcuts import reverse
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from cms import registry
|
||||
|
||||
MARKDOWN_EXTENSIONS = ['extra', 'smarty']
|
||||
register = template.Library()
|
||||
|
||||
|
@ -51,7 +53,7 @@ class IncludeSectionNode(template.Node):
|
|||
csrf_token = self.csrf_token.resolve(context)
|
||||
request = self.request.resolve(context)
|
||||
perms = self.perms.resolve(context)
|
||||
view = section.get_view(request)
|
||||
view = registry.get_view(section, request)
|
||||
section_context = view.get_context_data(
|
||||
csrf_token=csrf_token,
|
||||
section=section,
|
||||
|
|
59
cms/views.py
59
cms/views.py
|
@ -1,19 +1,39 @@
|
|||
import json
|
||||
import swapper
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from django.views.generic import base, detail, edit
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
|
||||
|
||||
from . import registry
|
||||
from .forms import PageForm, SectionForm
|
||||
|
||||
Page = swapper.load_model('cms', 'Page')
|
||||
Section = swapper.load_model('cms', 'Section')
|
||||
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
|
||||
|
||||
class PageView(detail.DetailView):
|
||||
'''View of a page with heterogeneous sections'''
|
||||
model = Page
|
||||
model = registry.page_class
|
||||
template_name = 'cms/page.html'
|
||||
|
||||
def setup(self, *args, slug='', **kwargs):
|
||||
|
@ -25,9 +45,14 @@ class PageView(detail.DetailView):
|
|||
try:
|
||||
page = self.object = self.get_object()
|
||||
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'])
|
||||
raise
|
||||
else:
|
||||
raise
|
||||
context = self.get_context_data(**kwargs)
|
||||
sections = page.sections.all()
|
||||
context.update({
|
||||
|
@ -48,7 +73,7 @@ class PageView(detail.DetailView):
|
|||
sections = page.sections.all()
|
||||
for section in sections:
|
||||
if section.pk == pk:
|
||||
view = section.get_view(request)
|
||||
view = registry.get_view(section, request)
|
||||
result = view.post(request)
|
||||
if isinstance(result, HttpResponse):
|
||||
return result
|
||||
|
@ -62,7 +87,7 @@ class PageView(detail.DetailView):
|
|||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
pages = Page.objects.filter(menu=True)
|
||||
pages = registry.page_class.objects.filter(menu=True)
|
||||
context.update({
|
||||
'pages': pages,
|
||||
})
|
||||
|
@ -70,7 +95,7 @@ class PageView(detail.DetailView):
|
|||
|
||||
class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View):
|
||||
'''Base view with nested forms for editing the page and all its sections'''
|
||||
model = Page
|
||||
model = registry.page_class
|
||||
form_class = PageForm
|
||||
template_name = 'cms/edit.html'
|
||||
|
||||
|
@ -88,7 +113,7 @@ class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMi
|
|||
def get_context_data(self, **kwargs):
|
||||
'''Populate the fields_per_type dict for use in javascript'''
|
||||
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
|
||||
|
||||
def get_object(self):
|
||||
|
@ -118,13 +143,13 @@ class EditPage(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMi
|
|||
class CreatePage(EditPage):
|
||||
'''View for creating new pages'''
|
||||
def get_object(self):
|
||||
return Page()
|
||||
return registry.page_class()
|
||||
|
||||
class UpdatePage(EditPage):
|
||||
'''View for editing existing pages'''
|
||||
|
||||
class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateResponseMixin, base.View):
|
||||
model = Section
|
||||
model = registry.section_class
|
||||
form_class = SectionForm
|
||||
template_name = 'cms/edit.html'
|
||||
|
||||
|
@ -140,20 +165,20 @@ class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateRespons
|
|||
|
||||
def get_context_data(self, **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
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
try:
|
||||
self.page = Page.objects.get(slug=self.kwargs['slug'])
|
||||
except Page.DoesNotExist:
|
||||
self.page = registry.page_class.objects.get(slug=self.kwargs['slug'])
|
||||
except registry.page_class.DoesNotExist:
|
||||
raise Http404()
|
||||
return self.get_section()
|
||||
|
||||
def get_section(self):
|
||||
try:
|
||||
section = self.page.sections.get(number=self.kwargs['number'])
|
||||
except Section.DoesNotExist:
|
||||
except self.page.sections.DoesNotExist:
|
||||
raise Http404()
|
||||
return section
|
||||
|
||||
|
@ -177,7 +202,7 @@ class EditSection(UserPassesTestMixin, edit.ModelFormMixin, base.TemplateRespons
|
|||
|
||||
class CreateSection(EditSection):
|
||||
def get_section(self):
|
||||
return Section(page=self.page)
|
||||
return registry.section_class(page=self.page)
|
||||
|
||||
class UpdateSection(EditSection):
|
||||
pass
|
||||
|
|
|
@ -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'],
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,24 +1,29 @@
|
|||
import cms
|
||||
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 _
|
||||
|
||||
@cms.register(_('Text'))
|
||||
class Text(cms.SectionView):
|
||||
@section_view
|
||||
class Text(SectionView):
|
||||
verbose_name = _('Text')
|
||||
fields = ['title', 'content']
|
||||
template_name = 'app/sections/text.html'
|
||||
|
||||
@cms.register(_('Images'))
|
||||
class Images(cms.SectionView):
|
||||
@section_view
|
||||
class Images(SectionView):
|
||||
verbose_name = _('Images')
|
||||
fields = ['title', 'images']
|
||||
template_name = 'app/sections/images.html'
|
||||
|
||||
@cms.register(_('Video'))
|
||||
class Video(cms.SectionView):
|
||||
@section_view
|
||||
class Video(SectionView):
|
||||
verbose_name = _('Video')
|
||||
fields = ['title', 'video']
|
||||
template_name = 'app/sections/video.html'
|
||||
|
||||
@cms.register(_('Contact'))
|
||||
class Contact(cms.SectionFormView):
|
||||
@section_view
|
||||
class Contact(SectionFormView):
|
||||
verbose_name = _('Contact')
|
||||
fields = ['title']
|
||||
form_class = ContactForm
|
||||
success_url = '/thanks/'
|
|
@ -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
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import embed_video.fields
|
||||
|
@ -32,6 +31,16 @@ 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=[
|
||||
|
@ -43,7 +52,7 @@ class Migration(migrations.Migration):
|
|||
('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')),
|
||||
('page', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sections', to='example.Page', verbose_name='page')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'section',
|
|
@ -1,21 +1,25 @@
|
|||
from django.db import models
|
||||
from cms.models import BasePage, BaseSection
|
||||
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):
|
||||
'''Add custom fields here. Already existing fields: title, slug,
|
||||
number, menu
|
||||
|
||||
'''
|
||||
|
||||
@section_model
|
||||
class Section(BaseSection):
|
||||
'''Add custom fields here. Already existing fields: title, type,
|
||||
number, content, image, video, href
|
||||
|
||||
'''
|
||||
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:
|
|
@ -1,19 +1,13 @@
|
|||
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'
|
||||
ADMINS = [('JJ Vens', 'jj@rtts.eu')]
|
||||
DEFAULT_FROM_EMAIL = 'noreply@rtts.eu'
|
||||
DEFAULT_TO_EMAIL = 'jj@rtts.eu'
|
||||
ALLOWED_HOSTS = ['*']
|
||||
ROOT_URLCONF = 'project.urls'
|
||||
WSGI_APPLICATION = 'project.wsgi.application'
|
||||
ROOT_URLCONF = PROJECT_NAME + '.urls'
|
||||
WSGI_APPLICATION = PROJECT_NAME + '.wsgi.application'
|
||||
LANGUAGE_CODE = 'nl'
|
||||
TIME_ZONE = 'Europe/Amsterdam'
|
||||
USE_I18N = True
|
||||
|
@ -24,8 +18,13 @@ STATIC_ROOT = '/srv/' + PROJECT_NAME + '/static'
|
|||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = '/srv/' + PROJECT_NAME + '/media'
|
||||
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):
|
||||
with open(file) as f:
|
||||
|
@ -40,7 +39,7 @@ except IOError:
|
|||
write(KEYFILE, SECRET_KEY)
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'app',
|
||||
PROJECT_NAME,
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
|
@ -3,7 +3,7 @@ import os
|
|||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
4
setup.py
4
setup.py
|
@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|||
|
||||
setup(
|
||||
name = 'django-simplecms',
|
||||
version = '2.3.1',
|
||||
version = '3.0.0',
|
||||
url = 'https://github.com/rtts/django-simplecms',
|
||||
author = 'Jaap Joris Vens',
|
||||
author_email = 'jj@rtts.eu',
|
||||
|
@ -15,11 +15,9 @@ setup(
|
|||
'django',
|
||||
'django-extensions',
|
||||
'django-embed-video',
|
||||
'django-polymorphic',
|
||||
'easy-thumbnails',
|
||||
'psycopg2',
|
||||
'markdown',
|
||||
'libsass',
|
||||
'swapper',
|
||||
],
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue