django-simplecms/cms/forms.py

152 wiersze
5.0 KiB
Python

import swapper
from django import forms
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')
class ConfirmationForm(forms.Form):
pass
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')
if len(body.split()) < 7:
return
spamcheck = self.cleaned_data.get('message')
if spamcheck != 'Hi there!':
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 Meta:
model = Page
fields = '__all__'
class SectionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 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'].widget.attrs['class'] = 'type'
self.fields['type'].widget.attrs['data-form'] = self.prefix
def delete(self):
instance = super().save()
instance.delete()
def save(self, commit=True):
section = super().save()
# Explanation: get the content type of the model that the user
# supplied when filling in this form, and save it's id to the
# 'polymorphic_ctype_id' field. The next time the object is
# requested from the database, django-polymorphic will convert
# it to the correct subclass.
section.polymorphic_ctype = ContentType.objects.get(
app_label=section._meta.app_label,
model=section.type.lower(),
)
if commit:
section.save()
return section
class Meta:
model = Section
exclude = ['page']
#field_classes = {
# 'type': forms.ChoiceField,
#}
# There is definitely a bug in Django, since the above 'field_classes' gets
# ignored entirely. Workaround to force a ChoiceField anyway:
type = forms.ChoiceField()
#SectionFormSet = inlineformset_factory(Page, Section, form=SectionForm, extra=1)
class BaseSectionFormSet(forms.BaseInlineFormSet):
'''If a swappable Section model defines one-to-many fields, (i.e. has
foreign keys pointing to it) formsets will be generated for the
related models and stored in the form.formsets array.
Based on this logic for nested formsets:
https://www.yergler.net/2013/09/03/nested-formsets-redux/
Typical usecases could be:
- an images section that displays multiple images
- a column section that displays separate colums
- a calendar section that displays calendar events
- etc...
'''
def add_fields(self, form, index):
super().add_fields(form, index)
section = form.instance
form.formsets = []
for field in section._meta.get_fields():
if field.one_to_many:
formset = forms.inlineformset_factory(Section, field.related_model, fields='__all__', extra=1)(
instance=section,
data=form.data if self.is_bound else None,
files=form.files if self.is_bound else None,
prefix=f'{form.prefix}-{field.name}')
formset.name = field.name
form.formsets.append(formset)
def is_valid(self):
result = super().is_valid()
if self.is_bound:
for form in self.forms:
for formset in form.formsets:
result = result and formset.is_valid()
return result
def save(self, commit=True):
result = super().save(commit=commit)
for form in self:
if hasattr(form, 'formset'):
form.formset.save(commit=commit)
return result
def get_form_kwargs(self, index):
kwargs = super().get_form_kwargs(index)
kwargs.update({'label_suffix': ''})
return kwargs
SectionFormSet = forms.inlineformset_factory(
parent_model = Page,
model = Section,
form = SectionForm,
formset = BaseSectionFormSet,
extra=1,
)
# class ImagesForm(forms.ModelForm):
# class Meta:
# model = SectionImage
# exclude = ['section']
# ImagesFormSet = forms.inlineformset_factory(Section, SectionImage, form=ImagesForm, extra=3)