Add AboutUsPage model and template to core app

This commit introduces the AboutUsPage model for managing content like company mission, vision, history, team, and additional content using Wagtail StreamFields. A corresponding template is provided for rendering the page. Required dependencies, including crispy-bootstrap3 and django-recaptcha, are also added to the project.
main
Arne Schauf 3 weeks ago
parent 79da93e56e
commit d57901962e
  1. 37
      core/migrations/0012_aboutuspage.py
  2. 71
      core/models.py
  3. 108
      core/templates/core/about_us_page.html
  4. 3
      feo_homepage/settings/base.py
  5. 1
      requirements.in
  6. 7
      requirements.txt

@ -0,0 +1,37 @@
# Generated by Django 5.2 on 2025-04-29 12:32
import django.db.models.deletion
import wagtail.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0011_alter_contactformfield_choices_and_more'),
('wagtailcore', '0094_alter_page_locale'),
]
operations = [
migrations.CreateModel(
name='AboutUsPage',
fields=[
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
('company_intro', wagtail.fields.RichTextField(blank=True, help_text='Introductory text about the company')),
('mission_title', models.CharField(blank=True, max_length=255)),
('mission_text', wagtail.fields.RichTextField(blank=True)),
('vision_title', models.CharField(blank=True, max_length=255)),
('vision_text', wagtail.fields.RichTextField(blank=True)),
('history_title', models.CharField(blank=True, max_length=255)),
('history_text', wagtail.fields.RichTextField(blank=True)),
('team_title', models.CharField(blank=True, max_length=255)),
('team_intro', wagtail.fields.RichTextField(blank=True)),
('team_members', wagtail.fields.StreamField([('team_member', 5)], blank=True, block_lookup={0: ('wagtail.blocks.CharBlock', (), {'max_length': 255}), 1: ('wagtail.images.blocks.ImageChooserBlock', (), {'required': False}), 2: ('wagtail.blocks.RichTextBlock', (), {'required': False}), 3: ('wagtail.blocks.EmailBlock', (), {'required': False}), 4: ('wagtail.blocks.URLBlock', (), {'required': False}), 5: ('wagtail.blocks.StructBlock', [[('name', 0), ('position', 0), ('photo', 1), ('bio', 2), ('email', 3), ('linkedin', 4), ('xing', 4)]], {})}, null=True)),
('additional_content', wagtail.fields.StreamField([('heading', 0), ('paragraph', 1), ('image', 2), ('quote', 5)], blank=True, block_lookup={0: ('wagtail.blocks.CharBlock', (), {'form_classname': 'full title'}), 1: ('wagtail.blocks.RichTextBlock', (), {}), 2: ('wagtail.images.blocks.ImageChooserBlock', (), {}), 3: ('wagtail.blocks.TextBlock', (), {}), 4: ('wagtail.blocks.CharBlock', (), {'required': False}), 5: ('wagtail.blocks.StructBlock', [[('quote', 3), ('attribution', 4)]], {})}, null=True)),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
]

@ -519,3 +519,74 @@ class UploadedScript(TimeStampedModel):
out = super().delete(*args, **kwargs)
storage.delete(path)
return out
class AboutUsPage(Page):
"""
A page for displaying company information, team members, mission statements, etc.
"""
# Company information
company_intro = RichTextField(
blank=True,
help_text="Introductory text about the company"
)
# Mission and vision
mission_title = models.CharField(max_length=255, blank=True)
mission_text = RichTextField(blank=True)
vision_title = models.CharField(max_length=255, blank=True)
vision_text = RichTextField(blank=True)
# Company history
history_title = models.CharField(max_length=255, blank=True)
history_text = RichTextField(blank=True)
# Team members section
team_title = models.CharField(max_length=255, blank=True)
team_intro = RichTextField(blank=True)
# Team members as a StreamField to allow adding multiple team members
team_members = StreamField([
('team_member', blocks.StructBlock([
('name', blocks.CharBlock(max_length=255)),
('position', blocks.CharBlock(max_length=255)),
('photo', ImageChooserBlock(required=False)),
('bio', blocks.RichTextBlock(required=False)),
('email', blocks.EmailBlock(required=False)),
('linkedin', blocks.URLBlock(required=False)),
('xing', blocks.URLBlock(required=False)),
])),
], null=True, blank=True, use_json_field=True)
# Additional content
additional_content = StreamField([
('heading', blocks.CharBlock(form_classname="full title")),
('paragraph', blocks.RichTextBlock()),
('image', ImageChooserBlock()),
('quote', blocks.StructBlock([
('quote', blocks.TextBlock()),
('attribution', blocks.CharBlock(required=False)),
])),
], null=True, blank=True, use_json_field=True)
AboutUsPage.content_panels = [
FieldPanel('title', classname="full title"),
FieldPanel('company_intro', classname="full"),
MultiFieldPanel([
FieldPanel('mission_title', classname="full"),
FieldPanel('mission_text', classname="full"),
FieldPanel('vision_title', classname="full"),
FieldPanel('vision_text', classname="full"),
], heading="Mission and Vision", classname="collapsible"),
MultiFieldPanel([
FieldPanel('history_title', classname="full"),
FieldPanel('history_text', classname="full"),
], heading="Company History", classname="collapsible"),
MultiFieldPanel([
FieldPanel('team_title', classname="full"),
FieldPanel('team_intro', classname="full"),
FieldPanel('team_members'),
], heading="Team Members", classname="collapsible"),
FieldPanel('additional_content', classname="full"),
]

@ -0,0 +1,108 @@
{% extends "core/base.html" %}
{% load core_tags menu_tags static wagtailuserbar wagtailcore_tags wagtailimages_tags %}
{% block content %}
<div class="container content">
<!-- Company Introduction -->
<div class="row margin-bottom-30">
<div class="col-md-12">
{{ self.company_intro|richtext }}
</div>
</div>
<!-- Mission and Vision -->
{% if self.mission_title or self.vision_title %}
<div class="row margin-bottom-30">
{% if self.mission_title %}
<div class="col-md-6 md-margin-bottom-30">
<div class="headline"><h2>{{ self.mission_title }}</h2></div>
{{ self.mission_text|richtext }}
</div>
{% endif %}
{% if self.vision_title %}
<div class="col-md-6">
<div class="headline"><h2>{{ self.vision_title }}</h2></div>
{{ self.vision_text|richtext }}
</div>
{% endif %}
</div>
{% endif %}
<!-- Company History -->
{% if self.history_title %}
<div class="row margin-bottom-30">
<div class="col-md-12">
<div class="headline"><h2>{{ self.history_title }}</h2></div>
{{ self.history_text|richtext }}
</div>
</div>
{% endif %}
<!-- Team Members -->
{% if self.team_title %}
<div class="row margin-bottom-30">
<div class="col-md-12">
<div class="headline"><h2>{{ self.team_title }}</h2></div>
{{ self.team_intro|richtext }}
</div>
</div>
<div class="row team-v1 margin-bottom-40">
{% for block in self.team_members %}
{% if block.block_type == 'team_member' %}
<div class="col-md-4 md-margin-bottom-30">
<div class="team-img">
{% if block.value.photo %}
{% image block.value.photo width-400 as team_photo %}
<img class="img-responsive" src="{{ team_photo.url }}" alt="{{ block.value.name }}">
{% endif %}
<ul>
{% if block.value.email %}
<li><a href="mailto:{{ block.value.email }}"><i class="fa fa-envelope"></i></a></li>
{% endif %}
{% if block.value.linkedin %}
<li><a href="{{ block.value.linkedin }}" target="_blank"><i class="fa fa-linkedin"></i></a></li>
{% endif %}
{% if block.value.xing %}
<li><a href="{{ block.value.xing }}" target="_blank"><i class="fa fa-xing"></i></a></li>
{% endif %}
</ul>
</div>
<h3>{{ block.value.name }}</h3>
<h4>{{ block.value.position }}</h4>
{% if block.value.bio %}
<p>{{ block.value.bio|richtext }}</p>
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
<!-- Additional Content -->
{% if self.additional_content %}
<div class="row margin-bottom-30">
<div class="col-md-12">
{% for block in self.additional_content %}
{% if block.block_type == 'heading' %}
<div class="headline"><h2>{{ block.value }}</h2></div>
{% elif block.block_type == 'paragraph' %}
{{ block.value|richtext }}
{% elif block.block_type == 'image' %}
{% image block.value width-800 as content_image %}
<img class="img-responsive margin-bottom-20" src="{{ content_image.url }}" alt="">
{% elif block.block_type == 'quote' %}
<blockquote>
<p>{{ block.value.quote }}</p>
{% if block.value.attribution %}
<small>{{ block.value.attribution }}</small>
{% endif %}
</blockquote>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
</div>
{% endblock content %}

@ -57,6 +57,8 @@ INSTALLED_APPS = [
'taggit',
'django_extensions',
'crispy_forms',
'crispy_bootstrap3',
'django_recaptcha',
'core',
]
@ -166,6 +168,7 @@ WAGTAILSEARCH_BACKENDS = {
# Base URL to use when referring to full URLs within the Wagtail admin backend
WAGTAILADMIN_BASE_URL = 'http://localhost:8000'
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap3"
CRISPY_TEMPLATE_PACK = 'bootstrap3'
RECAPTCHA_PUBLIC_KEY = '6Lfa2XAUAAAAAKaTdzFBc4zrN8YxrsW9kUpWjkom'

@ -6,5 +6,6 @@ django-extensions
icalendar
psycopg[binary]
django-crispy-forms
crispy-bootstrap3
django-braces
daphne

@ -28,6 +28,8 @@ charset-normalizer==3.4.1
# via requests
constantly==23.10.4
# via twisted
crispy-bootstrap3==2024.1
# via -r requirements.in
cryptography==44.0.2
# via
# autobahn
@ -40,6 +42,7 @@ defusedxml==0.7.1
django==5.2
# via
# -r requirements.in
# crispy-bootstrap3
# django-braces
# django-crispy-forms
# django-extensions
@ -58,7 +61,9 @@ django==5.2
django-braces==1.17.0
# via -r requirements.in
django-crispy-forms==2.4
# via -r requirements.in
# via
# -r requirements.in
# crispy-bootstrap3
django-extensions==4.1
# via -r requirements.in
django-filter==25.1

Loading…
Cancel
Save