A new templatetag 'includesection' now renders a section with its own

context, as provided by the polymorphic subsection's registered view.

Also, I'm trying to move all the website-related cruft from cms into the
example project, so that only the Page and Section models with their own
"admin" views will remain.
readwriteweb
Jaap Joris Vens 2020-01-05 03:36:23 +01:00
rodzic 9e1baf6ee1
commit 5f5f303187
23 zmienionych plików z 254 dodań i 130 usunięć

Wyświetl plik

@ -1,5 +1,4 @@
from django import forms from django import forms
from django.core.mail import EmailMessage
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -7,25 +6,6 @@ import swapper
Page = swapper.load_model('cms', 'Page') Page = swapper.load_model('cms', 'Page')
Section = swapper.load_model('cms', 'Section') Section = swapper.load_model('cms', 'Section')
class ContactForm(forms.Form):
sender = forms.EmailField(label=_('Your email address'))
spam_protection = forms.CharField(label=_('Your message'), widget=forms.Textarea())
message = forms.CharField(label=_('Your message'), widget=forms.Textarea(), initial='Hi there!')
def save(self, request):
hostname = request.get_host()
body = self.cleaned_data.get('spam_protection') # MUHAHA
if len(body.split()) < 7:
return
email = EmailMessage(
to = ['info@' + hostname],
from_email = 'noreply@' + hostname,
body = body,
subject = _('Contact form at %(hostname)s.') % {'hostname': hostname},
headers = {'Reply-To': self.cleaned_data.get('sender')},
)
email.send()
class PageForm(forms.ModelForm): class PageForm(forms.ModelForm):
class Meta: class Meta:
model = Page model = Page

Wyświetl plik

@ -1,11 +1,10 @@
# Generated by Django 3.0.1 on 2020-01-02 20:41 # Generated by Django 3.0.2 on 2020-01-04 22:55
import cms.models import cms.models
from django.conf import settings 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
import markdownfield.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -21,9 +20,9 @@ class Migration(migrations.Migration):
name='Page', name='Page',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('title', cms.models.VarCharField(verbose_name='title')),
('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')), ('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')),
('title', cms.models.VarCharField(verbose_name='title')),
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('menu', models.BooleanField(default=True, verbose_name='visible in menu')), ('menu', models.BooleanField(default=True, verbose_name='visible in menu')),
], ],
options={ options={
@ -38,12 +37,10 @@ class Migration(migrations.Migration):
name='Section', name='Section',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', cms.models.VarCharChoiceField(choices=[('textsection', 'Tekst'), ('imagesection', 'Afbeelding'), ('contactsection', 'Contact')], default='', verbose_name='section type')), ('type', cms.models.VarCharChoiceField(choices=[('textsection', 'Tekst'), ('imagesection', 'Afbeelding'), ('contactsection', 'Contact')], default='', verbose_name='type')),
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('title', cms.models.VarCharField(blank=True, verbose_name='title')), ('title', cms.models.VarCharField(blank=True, verbose_name='title')),
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')), ('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('content', markdownfield.models.MarkdownField(blank=True, verbose_name='content')), ('content', models.TextField(blank=True, verbose_name='content')),
('content_rendered', markdownfield.models.RenderedMarkdownField(editable=False)),
('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')),
('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')), ('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')),

Wyświetl plik

@ -4,13 +4,10 @@ import swapper
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.conf import settings
from django.forms import TextInput, Select from django.forms import TextInput, Select
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from embed_video.fields import EmbedVideoField from embed_video.fields import EmbedVideoField
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
from markdownfield.models import MarkdownField, RenderedMarkdownField
from markdownfield.validators import VALIDATOR_NULL
from numberedmodel.models import NumberedModel from numberedmodel.models import NumberedModel
@ -56,9 +53,7 @@ class BaseSection(NumberedModel, PolymorphicModel):
type = VarCharChoiceField(_('type'), default='', choices=TYPES) type = VarCharChoiceField(_('type'), default='', choices=TYPES)
title = VarCharField(_('title'), blank=True) title = VarCharField(_('title'), blank=True)
position = models.PositiveIntegerField(_('position'), blank=True) position = models.PositiveIntegerField(_('position'), blank=True)
color = models.PositiveIntegerField(_('color'), default=1, choices=settings.SECTION_COLORS) content = models.TextField(_('content'), blank=True)
content = MarkdownField(_('content'), rendered_field='content_rendered', validator=VALIDATOR_NULL, use_admin_editor=False, blank=True)
content_rendered = RenderedMarkdownField()
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'))
button_text = VarCharField(_('button text'), blank=True) button_text = VarCharField(_('button text'), blank=True)

Wyświetl plik

@ -0,0 +1,7 @@
{% load i18n %}
{% if request.user.is_staff %}
<div class="edit">
<a href="{% url 'cms:updatesection' section.pk %}">{% trans 'edit this section' %}</a>
</div>
{% endif %}

Wyświetl plik

@ -1,13 +1,12 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n %} {% load i18n %}
{% load cms %}
{% block title %}{{block.super}} - {{page.title}}{% endblock %} {% block title %}{{block.super}} - {{page.title}}{% endblock %}
{% block content %} {% block content %}
{% for section in sections %} {% for section in sections %}
<section class="{{section.type}} color{{section.color}}"> {% include_section section %}
{% include 'cms/sections/'|add:section.type|lower|add:'.html' %}
</section>
{% endfor %} {% endfor %}
<div class="edit page"> <div class="edit page">

Wyświetl plik

@ -1,6 +1,7 @@
{% load i18n thumbnail embed_video_tags %} {% load i18n thumbnail embed_video_tags %}
{% load markdown %}
{% block section %} <section class="{{section.type}} color{{section.color}}">
<div class="wrapper"> <div class="wrapper">
{% if section.image %} {% if section.image %}
@ -17,9 +18,9 @@
</div> </div>
{% endif %} {% endif %}
{% if section.content_rendered %} {% if section.content %}
<div class="content"> <div class="content">
{{section.content_rendered|safe}} {{section.content|markdown}}
</div> </div>
{% endif %} {% endif %}
@ -31,32 +32,12 @@
</div> </div>
{% endif %} {% endif %}
{% if section.subsections.exists %}
<div class="subsections">
{% for sub in section.subsections.all %}
<div class="subsection color{{sub.color}}">
{% with section=sub user=None %}
{% include 'cms/sections/base.html' %}
{% endwith %}
</div>
{% endfor %}
</div>
{% endif %}
{% if section.button_text %} {% if section.button_text %}
<div class="button"> <div class="button">
<a class="button" href="{{section.button_link}}">{{section.button_text}}</a> <a class="button" href="{{section.button_link}}">{{section.button_text}}</a>
</div> </div>
{% endif %} {% endif %}
</div>
{% endblock %}
{% block extracontent %}{% endblock %} {% include 'cms/editlink.html' %}
{% if user.is_staff %}
<div class="wrapper">
<div class="edit">
<a href="{% url 'cms:updatesection' section.pk %}">{% trans 'edit this section' %}</a>
</div>
</div> </div>
{% endif %} </section>

Wyświetl plik

@ -0,0 +1,29 @@
from django import template
register = template.Library()
@register.tag('include_section')
def do_include(parser, token):
'''Renders the section with its own context
'''
_, section = token.split_contents()
return IncludeSectionNode(section)
class IncludeSectionNode(template.Node):
def __init__(self, section):
self.section = template.Variable(section)
self.csrf_token = template.Variable('csrf_token')
super().__init__()
def render(self, context):
section = self.section.resolve(context)
template_name = section.view.template_name
if template_name is None:
raise ValueError(f'{section} view has no template_name attribute')
csrf_token = self.csrf_token.resolve(context)
if not hasattr(section, 'context'):
raise ValueError(dir(section))
section.context.update({'csrf_token': csrf_token})
t = context.template.engine.get_template(template_name)
return t.render(template.Context(section.context))

Wyświetl plik

@ -0,0 +1,15 @@
from markdown import markdown as md
from django import template
from django.conf import settings
from django.utils.safestring import mark_safe
EXTENSIONS = getattr(settings, 'MARKDOWN_EXTENSIONS', [])
register = template.Library()
@register.filter(is_safe=True)
def markdown(value):
'''Runs Markdown over a given value
'''
return mark_safe(md(value, extensions=EXTENSIONS))

Wyświetl plik

@ -9,8 +9,6 @@ urlpatterns = [
path('updatesection/<int:pk>/', UpdateSection.as_view(), name='updatesection'), path('updatesection/<int:pk>/', UpdateSection.as_view(), name='updatesection'),
path('createpage/', CreatePage.as_view(), name='createpage'), path('createpage/', CreatePage.as_view(), name='createpage'),
path('createsection/<int:pk>', CreateSection.as_view(), name='createsection'), path('createsection/<int:pk>', CreateSection.as_view(), name='createsection'),
# Feel free to copy the following into your root URL conf!
path('', PageView.as_view(), name='page'), path('', PageView.as_view(), name='page'),
path('<slug:slug>/', PageView.as_view(), name='page'), path('<slug:slug>/', PageView.as_view(), name='page'),
] ]

Wyświetl plik

@ -4,6 +4,7 @@ import json
import swapper import swapper
from django.views import generic from django.views import generic
from django.views.generic.edit import FormMixin
from django.shortcuts import redirect from django.shortcuts import redirect
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -19,43 +20,27 @@ Section = swapper.load_model('cms', 'Section')
@register_view(Section) @register_view(Section)
class SectionView: class SectionView:
'''Generic section view''' '''Generic section view'''
def get(self, request, section): template_name = 'cms/sections/section.html'
'''Override this to add custom attributes to a section'''
return section
class SectionWithFormView(SectionView): def setup(self, request, section):
'''Initialize request and section attributes'''
self.request = request
self.section = section
def get_context_data(self, **kwargs):
'''Override this to customize a section's context'''
return kwargs
class SectionFormView(FormMixin, SectionView):
'''Generic section with associated form''' '''Generic section with associated form'''
form_class = None
success_url = None
def get_form_class(self): def post(self, request):
'''Return the form class to use in this view.'''
if self.form_class:
return self.form_class
raise ImproperlyConfigured(
'Either specify formclass attribute or override get_form_class()')
def get_success_url(self):
'''Return the URL to redirect to after processing a valid form.'''
if self.success_url:
return self.success_url
raise ImproperlyConfigured(
'Either specify success_url attribute or override get_success_url()')
def get(self, request, section):
'''Add form to section'''
form = self.get_form_class()()
section.form = form
return section
def post(self, request, section):
'''Process form''' '''Process form'''
form = self.get_form_class()(request.POST, request.FILES) form = self.get_form()
if form.is_valid(): if form.is_valid():
form.save(request) form.save(request)
return redirect(self.get_success_url()) return redirect(self.get_success_url())
section.form = form return form
return section
class MenuMixin: class MenuMixin:
'''Add pages to template context''' '''Add pages to template context'''
@ -83,14 +68,21 @@ class PageView(MenuMixin, MemoryMixin, generic.DetailView):
'''Supply a default argument for slug''' '''Supply a default argument for slug'''
super().setup(*args, slug=slug, **kwargs) super().setup(*args, slug=slug, **kwargs)
def initialize_section(self, section):
section.view = section.__class__.view_class()
section.view.setup(self.request, section)
section.context = section.view.get_context_data(
request = self.request,
section = section,
)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
'''Call each sections's get() view before rendering final response''' '''Initialize sections and render final response'''
page = self.object = self.get_object() page = self.object = self.get_object()
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
sections = page.sections.all() sections = page.sections.all()
for section in sections: for section in sections:
view = section.__class__.view_class() self.initialize_section(section)
view.get(request, section)
context.update({ context.update({
'page': page, 'page': page,
'sections': sections, 'sections': sections,
@ -98,7 +90,8 @@ class PageView(MenuMixin, MemoryMixin, generic.DetailView):
return self.render_to_response(context) return self.render_to_response(context)
def post(self, request, **kwargs): def post(self, request, **kwargs):
'''Call the post() function of the correct section view''' '''Initialize sections and call the post() function of the correct
section view'''
try: try:
pk = int(self.request.POST.get('section')) pk = int(self.request.POST.get('section'))
except: except:
@ -108,20 +101,20 @@ class PageView(MenuMixin, MemoryMixin, generic.DetailView):
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
sections = page.sections.all() sections = page.sections.all()
for section in sections: for section in sections:
view = section.__class__.view_class() self.initialize_section(section)
if section.pk == pk: if section.pk == pk:
result = view.post(request, section) result = section.view.post(request)
if isinstance(result, HttpResponseRedirect): if isinstance(result, HttpResponseRedirect):
return result return result
else: section.context['form'] = result
view.get(request, section)
context.update({ context.update({
'page': page, 'page': page,
'sections': sections, 'sections': sections,
}) })
return self.render_to_response(context) return self.render_to_response(context)
# The following views all require a logged-in staff member # The following views require a logged-in staff member
class StaffRequiredMixin(UserPassesTestMixin): class StaffRequiredMixin(UserPassesTestMixin):
def test_func(self): def test_func(self):

Wyświetl plik

@ -0,0 +1,22 @@
from django import forms
from django.core.mail import EmailMessage
from django.utils.translation import gettext_lazy as _
class ContactForm(forms.Form):
sender = forms.EmailField(label=_('Your email address'))
spam_protection = forms.CharField(label=_('Your message'), widget=forms.Textarea())
message = forms.CharField(label=_('Your message'), widget=forms.Textarea(), initial='Hi there!')
def save(self, request):
hostname = request.get_host()
body = self.cleaned_data.get('spam_protection') # MUHAHA
if len(body.split()) < 7:
return
email = EmailMessage(
to = ['info@' + hostname],
from_email = 'noreply@' + hostname,
body = body,
subject = _('Contact form at %(hostname)s.') % {'hostname': hostname},
headers = {'Reply-To': self.cleaned_data.get('sender')},
)
email.send()

Wyświetl plik

@ -1,11 +1,10 @@
# Generated by Django 3.0.1 on 2020-01-02 20:42 # Generated by Django 3.0.2 on 2020-01-05 02:29
import cms.models import cms.models
from django.conf import settings 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
import markdownfield.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -13,8 +12,8 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.CMS_PAGE_MODEL),
('contenttypes', '0002_remove_content_type_name'), ('contenttypes', '0002_remove_content_type_name'),
migrations.swappable_dependency(settings.CMS_PAGE_MODEL),
] ]
operations = [ operations = [
@ -22,9 +21,9 @@ class Migration(migrations.Migration):
name='Page', name='Page',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('title', cms.models.VarCharField(verbose_name='title')),
('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')), ('slug', models.SlugField(blank=True, help_text='A short identifier to use in URLs', unique=True, verbose_name='slug')),
('title', cms.models.VarCharField(verbose_name='title')),
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('menu', models.BooleanField(default=True, verbose_name='visible in menu')), ('menu', models.BooleanField(default=True, verbose_name='visible in menu')),
], ],
options={ options={
@ -38,16 +37,15 @@ class Migration(migrations.Migration):
name='Section', name='Section',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', cms.models.VarCharChoiceField(choices=[('textsection', 'Tekst'), ('imagesection', 'Afbeelding'), ('contactsection', 'Contact')], default='', verbose_name='section type')), ('type', cms.models.VarCharChoiceField(choices=[('textsection', 'Tekst'), ('buttonsection', 'Button'), ('imagesection', 'Afbeelding'), ('videosection', 'Video'), ('contactsection', 'Contact')], default='', verbose_name='type')),
('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('title', cms.models.VarCharField(blank=True, verbose_name='title')), ('title', cms.models.VarCharField(blank=True, verbose_name='title')),
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='color')), ('position', models.PositiveIntegerField(blank=True, verbose_name='position')),
('content', markdownfield.models.MarkdownField(blank=True, verbose_name='content')), ('content', models.TextField(blank=True, verbose_name='content')),
('content_rendered', markdownfield.models.RenderedMarkdownField(editable=False)),
('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')),
('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')), ('button_text', cms.models.VarCharField(blank=True, verbose_name='button text')),
('button_link', cms.models.VarCharField(blank=True, verbose_name='button link')), ('button_link', cms.models.VarCharField(blank=True, verbose_name='button link')),
('color', models.PositiveIntegerField(choices=[(1, 'Wit')], default=1, verbose_name='kleur')),
('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=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_app.section_set+', to='contenttypes.ContentType')), ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_app.section_set+', to='contenttypes.ContentType')),
], ],
@ -58,6 +56,17 @@ class Migration(migrations.Migration):
'abstract': False, 'abstract': False,
}, },
), ),
migrations.CreateModel(
name='ButtonSection',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('app.section',),
),
migrations.CreateModel( migrations.CreateModel(
name='ContactSection', name='ContactSection',
fields=[ fields=[
@ -91,4 +100,15 @@ class Migration(migrations.Migration):
}, },
bases=('app.section',), bases=('app.section',),
), ),
migrations.CreateModel(
name='VideoSection',
fields=[
],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('app.section',),
),
] ]

Wyświetl plik

@ -1,3 +1,5 @@
from django.db import models
from django.conf import settings
from cms.models import BasePage, BaseSection from cms.models import BasePage, BaseSection
from cms.decorators import register_model from cms.decorators import register_model
@ -9,13 +11,20 @@ class Page(BasePage):
class Section(BaseSection): class Section(BaseSection):
'''Add custom fields here. Already existing fields: type, position, '''Add custom fields here. Already existing fields: type, position,
title, color, content, image, video, button_text, button_link title, content, image, video, button_text, button_link
''' '''
color = models.PositiveIntegerField('kleur', default=1, choices=settings.SECTION_COLORS)
@register_model('Tekst') @register_model('Tekst')
class TextSection(Section): class TextSection(Section):
fields = ['type', 'position', 'title', 'content'] fields = ['type', 'position', 'title', 'color', 'content']
class Meta:
proxy = True
@register_model('Button')
class ButtonSection(Section):
fields = ['type', 'position', 'title', 'button_text', 'button_link']
class Meta: class Meta:
proxy = True proxy = True
@ -25,6 +34,12 @@ class ImageSection(Section):
class Meta: class Meta:
proxy = True proxy = True
@register_model('Video')
class VideoSection(Section):
fields = ['type', 'position', 'title', 'video']
class Meta:
proxy = True
@register_model('Contact') @register_model('Contact')
class ContactSection(Section): class ContactSection(Section):
fields = ['type', 'position', 'title'] fields = ['type', 'position', 'title']

Wyświetl plik

@ -0,0 +1,11 @@
<section class="{{section.type}} color{{section.color}}">
<div class="wrapper">
{% if section.button_text %}
<div class="button">
<a class="button" href="{{section.button_link}}">{{section.button_text}}</a>
</div>
{% endif %}
{% include 'cms/editlink.html' %}
</div>
</section>

Wyświetl plik

@ -1,7 +1,6 @@
{% extends 'cms/sections/base.html' %}
{% load i18n %} {% load i18n %}
{% block section %} <section class="{{section.type}} color{{section.color}}">
<div class="wrapper"> <div class="wrapper">
<div class="title"> <div class="title">
<h1>{{section.title}}</h1> <h1>{{section.title}}</h1>
@ -10,12 +9,13 @@
<div class="form"> <div class="form">
<form method="post" class="cms"> <form method="post" class="cms">
{% csrf_token %} {% csrf_token %}
{% for field in section.form %} {% for field in form %}
{% include 'cms/formfield.html' with field=field %} {% include 'cms/formfield.html' with field=field %}
{% endfor %} {% endfor %}
<button class="button" name="section" value="{{section.pk}}">{% trans 'Send' %}</button> <button class="button" name="section" value="{{section.pk}}">{% trans 'Send' %}</button>
</form> </form>
</div> </div>
{% include 'cms/editlink.html' %}
</div> </div>
{% endblock %} </section>

Wyświetl plik

@ -0,0 +1,14 @@
{% load thumbnail %}
<section class="{{section.type}} color{{section.color}}">
<div class="wrapper">
{% if section.image %}
<div class="image">
<img alt="{{section.title}}" src="{% thumbnail section.image 800x800 %}">
</div>
{% endif %}
{% include 'cms/editlink.html' %}
</div>
</section>

Wyświetl plik

@ -0,0 +1,21 @@
{% load markdown %}
<section class="{{section.type}} color{{section.color}}">
<div class="wrapper">
{% if section.title %}
<div class="title">
<h1>
{{section.title}}
</h1>
</div>
{% endif %}
{% if section.content %}
<div class="content">
{{section.content|markdown}}
</div>
{% endif %}
{% include 'cms/editlink.html' %}
</div>
</section>

Wyświetl plik

@ -0,0 +1,16 @@
{% load embed_video_tags %}
<section class="{{section.type}} color{{section.color}}">
<div class="wrapper">
{% if section.video %}
<div class="video">
<div class="iframe">
{% video section.video '800x600' %}
</div>
</div>
{% endif %}
{% include 'cms/editlink.html' %}
</div>
</section>

Wyświetl plik

@ -1 +0,0 @@
{% extends 'cms/sections/base.html' %}

Wyświetl plik

@ -1 +0,0 @@
{% extends 'cms/sections/base.html' %}

Wyświetl plik

@ -1,10 +1,27 @@
from cms.forms import ContactForm from cms.views import SectionView, SectionFormView
from cms.views import SectionWithFormView
from cms.decorators import register_view from cms.decorators import register_view
from .models import * from .models import *
from .forms import ContactForm
@register_view(TextSection)
class TextView(SectionView):
template_name = 'app/sections/text.html'
@register_view(ButtonSection)
class ButtonView(SectionView):
template_name = 'app/sections/button.html'
@register_view(ImageSection)
class ImageView(SectionView):
template_name = 'app/sections/image.html'
@register_view(VideoSection)
class VideoView(SectionView):
template_name = 'app/sections/video.html'
@register_view(ContactSection) @register_view(ContactSection)
class ContactFormView(SectionWithFormView): class ContactFormView(SectionFormView):
form_class = ContactForm form_class = ContactForm
success_url = '/thanks/' success_url = '/thanks/'
template_name = 'app/sections/contact.html'

Wyświetl plik

@ -7,7 +7,6 @@ except ImportError:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
PROJECT_NAME = 'example' PROJECT_NAME = 'example'
SITE_URL = 'https://example.com/'
KEYFILE = f'/tmp/{PROJECT_NAME}.secret' KEYFILE = f'/tmp/{PROJECT_NAME}.secret'
ADMINS = [('JJ Vens', 'jj@rtts.eu')] ADMINS = [('JJ Vens', 'jj@rtts.eu')]
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
@ -25,7 +24,6 @@ MEDIA_ROOT = '/srv/' + PROJECT_NAME + '/media'
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
CMS_SECTION_MODEL = 'app.Section' CMS_SECTION_MODEL = 'app.Section'
MARKDOWN_EXTENSIONS = ['extra', 'smarty'] MARKDOWN_EXTENSIONS = ['extra', 'smarty']
MARKDOWN_EXTENSION_CONFIGS = {'extra': {}, 'smarty': {}}
def read(file): def read(file):
with open(file) as f: with open(file) as f:

Wyświetl plik

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