Features¶
Responsive Images¶
Responsive images adapt to different screen sizes, ensuring optimal display across devices. This project uses two types of responsive images:
Normal Images: Displayed within page content.
Thumbnail Images: Shown as thumbnails in content and enlarged in a modal upon clicking.
Image Renditions: For each image, three renditions are created in AVIF and JPEG formats: - 1x Width: Standard size, used in the src attribute of the img tag. - 2x Width: Double size, used provided the image is not larger or nearly the same size as the original. - 3x Width: Triple size, used only when necessary. These renditions are specified in the srcset attribute of the source or img elements.
Those three renditions are put into the srcset attribute of the related source or img elements.
Normal Images¶
Normal images fill a slot with a width of 1110px and a maximum height of 740px. But you can configure those values in the settings.
Therefore, if you have an image which is quadratic and has a width of 3000px it will rendered with a maximum width of 740px, but delivered with a width of 2220px to high pixel density devices.
Both AVIF and JPEG formats are supported.
Thumbnail Images¶
Thumbnail images have a width of 120px and a maximum height of 80px. But you can also set those values in the settings.
They also support AVIF and JPEG formats.
Frontend¶
Pagination¶
The blog index page comes with pagination support. You can set the number of posts per page using the POST_LIST_PAGINATION setting.
If there are more then 3 pages, there will be a “…” in the pagination. If there are more then 10 pages, there will be two “…” in the pagination.
Django-Admin¶
The file sizes of an audio object are cached automatically. But for old audio objects there’s an admin action where you can update the file size cache for all associated audio files.
Blog¶
Title¶
The title field is used to populate the title attribute in the feed. And it is also used in the default templates to display the title of the blog on the blog index page.
Subtitle¶
The subtitle field is used to populate the subtitle attribute on the podlove player.
Description¶
The description field is used to populate the description attribute in the feed. And it is also used in the default templates to display a short description of the blog on the blog index page.
Email¶
Contact address for the blog.
Template Base Dir¶
The template_base_dir field is used to specify the base directory for the templates used to render the blog. It’s basically a theme switcher.
Cover Image¶
The cover_image field is used to specify the cover image for the blog. If posts have no cover image, the blog cover image will be used as a fallback. There’s a cover_alt_text field to specify the alt text for the cover image.
Promote > Title¶
This title is show in search engine results linking to the blog.
Promote > Description¶
This description is show in search engine results linking to the blog.
Promote > NoIndex¶
If you set the custom BooleanField field named noindex on a Blog-Page using the Wagtail or Django-Admin interface, the Page and all its subpages will be excluded from being indexed by search engines.
Post¶
Posts are Wagtail pages that have a blog page as a parent.
Visible Date¶
You can set the visible_date of a post, which will be showed in templates and used for sorting posts shown on the blog index page.
Cover Image¶
The cover image for a post is used for meta tags like twitter:image or og:image. But you can also use it in the templates for the blog index page or the post detail page. If you set cover_alt_text, it can be used as the alt attribute of the cover image.
For posts without a cover image, the blog’s cover image will be used. Alternatively, I often generate one using the shot-scraper tool:
pipx install shot-scraper
shot-scraper install # installs chromium headless
shot-scraper shot https://wersdoerfer.de/blogs/ephes_blog/ -w 800 -h 400 --retina --quality 60
This will generate a screenshot of the blog post and save it as a jpeg. But you can also use png. It is also possible to set a separate alt text for the cover image.
Promote > Title¶
There is a field called title in the promote tab of the Wagtail admin which is used to set the title of the post for search engine results as the clickable headline. This will also be used for the og:title and twitter:title meta tags.
Promote > Description¶
The description field in the promote tab of the Wagtail admin is used to set the description of the post for search engine results. This will also be used for the og:description and twitter:description meta tags.
Body¶
The body of a post is a StreamField. You can add different types of blocks to the body of a post. There are two types of blocks you can add to the body of a post:
1. Overview¶
Overview blocks are used to display a summary of the post on the blog index page or in feeds.
2. Detail¶
Detail blocks are used to display the full content of the post. Usually it is shown on the post detail page.
Types of Blocks¶
Inside the Overview and Detail blocks following types of blocks are available:
Heading
Paragraph - Rich Text which can include headings, images, links, etc.
Image - A single image
Gallery with Layout - A gallery of images with different layout options
Embed - Embed a video or other content from a URL
Audio - Displayed using the Podlove Web Player
Code - Code block with syntax highlighting
Podcast¶
Podcasts are blogs that have some additional features to better support podcasting.
There are some additional fields that are available for podcasts:
Itunes Artwork¶
The image that will be used in the podcast feed as the iTunes artwork.
Episode¶
Podcast episodes are Wagtail pages that have a podcast page as a parent. They have the same features as blog posts, but with some additional fields for better podcast support.
Cover Image¶
In addition to the effect setting a cover image for a post has, setting a cover image for an episode will also be used as the episode’s artwork in the podcast feed and in the Podlove Web Player.
If no cover image is set for the episode, the blog’s cover image will be used.
Podcast Audio¶
The podcast_audio field is required for an episode. It is used for the enclosure tag in the podcast feed.
Promote > Title¶
This will be used as the title of the episode in the Podlove Web Player.
Promote > Description¶
This will be used as the description of the episode in the Podlove Web Player.
Keywords¶
Keywords are set in the podcast feed as the iTunes keywords tag.
Explicit¶
Explicit content is set in the podcast feed as the iTunes explicit tag.
Block¶
Indicates whether the episode is blocked from iTunes or not.
Image¶
Images are mostly just the normal Wagtail Images. But they are rendered using a picture tag supporting srcset and sizes attributes for responsive images.
Gallery¶
Galleries are a collection of images. They are used to display a list of thumbnails and a larger view of the selected image. See responsive images for more information about thumbnails.
Video¶
You can upload video files to the server and play them back in the browser.
Videos have a title a file field original pointing to the original video file, an image poster and a list of tags.
If no poster is given, the first frame of the video after one second is used as poster.
Audio¶
You can upload audio files to the server and play them back in the browser.
Audio Models¶
Audio files are represented by the Audio model. Audio files have a title, a subtitle, tags and four file fields pointing to the file in different audio formats:
m4a - AAC, works best on Apple/iOS devices
mp3 - MP3, works everywhere, but has no time index so the whole file has to be downloaded before playback can start
oga - OGG Vorbis, maybe remove this one because apple is now adding support for opus, too
opus - Opus, better quality per bitrate than all other formats, but not as well known as the others
Since podcast feeds only support one audio file per episode, there is one feed per audio format. The feeds are generated automatically and can be found at feed/podcast/<audio_format>/rss.xml.
Playback¶
For playback of audio content Podlove Web Player version 5 is used.
Hint
Currently supported features:
Chapter marks
Download button
Templates / Themes¶
You can choose different templates for the entire website or for specific blogs / podcasts. All users can select these templates from the Wagtail admin interface. Individual users can make their own template selections, which are stored in their session.
Plain HTML (plain) - This is just a plain HTML template without any CSS
Bootstrap 4 (bootstrap4) - This is a template that uses Bootstrap 4 and is currently the default template
Bootstrap 5 (bootstrap5) - This is a template that uses Bootstrap 5 and is the theme that I usually use for my own projects
Vue.js - This is a template that uses Vue.js and demonstrates how to combine an SPA frontend with django-cast
If you want to use your own templates, you can do so by overwriting the built-in templates or creating a new directory in your project’s templates directory and name it cast/{your_template_name}. Then you can create your own templates in this directory. After all of the following template names are added, you should be able to select your custom template in the Wagtail admin interface.
Important
This is the minimal list of templates that have to be implemented for a template named minimal:
cast/minimal/base.html
cast/minimal/blog_list_of_posts.html
cast/minimal/post.html
cast/minimal/post_body.html
cast/minimal/episode.html
cast/minimal/select_template.html
Hint
It’s only possible to create own template themes with template
loaders that implement the get_dirs method (FilesystemLoader,
CachedLoader). If you want to use a template loader that doesn’t
implement the get_dirs method, you have to add it to
settings.CAST_CUSTOM_THEMES
.
An list of additional templates that can be overwritten:
cast/custom/audio.html
Galleries¶
Galleries can have different layouts. Currently there are two layouts:
default - This is the default layout which will use the cast/minimal/gallery.html template
htmx - Which will use the cast/minimal/gallery_htmx.html template
If you don’t want to implement the htmx layout, you can just copy your cast/minimal/gallery.html template to cast/minimal/gallery_htmx.html.
How to Change the Theme for the whole Site¶
This setting can be found at settings > Template base directory:
There’s a context processor that adds the current template base directory aka theme to the context. For convenience it also adds the theme’s base template as a variable to the context to be able to extend it in non Wagtail templates.
Error Views¶
If you want to use your own error views, you can do so by creating templates for each error code in your theme’s directory.
Hint
This is the list of templates that you can overwrite
cast/your_theme/404.html
cast/your_theme/500.html
cast/your_theme/400.html
cast/your_theme/403.html
cast/your_theme/403_csrf.html
Since now the error views need to know which theme to use, you have to overwrite the default error views in your project’s root URL-conf:
...
from cast.views import defaults as default_views_cast
handler404 = default_views_cast.page_not_found
handler500 = default_views_cast.server_error
handler400 = default_views_cast.bad_request
handler403 = default_views_cast.permission_denied
Setting the view for the 403_csrf error is a special case. You have to specify the view in your project’s settings:
...
# view handling csrf failures
CSRF_FAILURE_VIEW = "cast.views.defaults.csrf_failure"
How to Change the Theme for a Single Blog¶
This setting can be found at pages > … > Blog:
How to Change the Theme for an Individual User¶
The theme selection for an individual user is stored in request.session and does overwrite blog and site level theme settings.
JSON-Api¶
You can get a list of selectable themes via the cast:api:theme-list endpoint. This endpoint will also show the currently selected theme. If you want to update the selected theme, you can do so via cast:api:theme-update.
Hypermedia¶
The hypermedia endpoints for getting / setting the theme are:
cast:theme-list - List of all themes (the currently selected theme is marked)
cast:theme-update - Update the theme for the current user
Django-Admin Commands¶
There are some management-commands bundled with django-cast. Most of them are dealing with the management of media files.
recalc_video_posters
: Recalculate the poster images for all videos.media_backup
: Backup media files from production to backup storage backend (requires Django >= 4.2).media_sizes
: Print the sizes of all media files stored in the production storage backend (requires Django >= 4.2).media_replace
: Replace files on production storage backend with versions from local file system (requires Django >= 4.2). This might be useful for videos for which you now have a better compressed version, but you don’t want to generate a new name.media_restore
: Restore media files from backup storage backend to production storage backend (requires Django >= 4.2).media_stale
: Print the paths of all media files stored in the production storage backend that are not referenced in the database (requires Django >= 4.2).sync_renditions
: Create missing renditions for images and remove obsolete ones. Useful if you have changed the rendition sizes in your settings or added new image formats.
Comments¶
You can enable / disable comments on app, blog and post-level. For app-level, there’s a global switch you can use in the settings. Blog and post models have a comments_enabled database field. They are set to
True
by default.Caveats¶
The ajax-calls django-fluent-comments does depend on the availability of a full jquery version.
Comment Spam Filter¶
There’s a simple Naive Bayes-based spam filter for comments built in. It’s not very smart, but it’s good enough to filter out most spam. It’s also very easy to train and very fast to run. And it’s only slightly above one hundred lines of pure Python code.
A comment is considered ham if it’s public and not removed. All other comments are considered spam. It’s possible to re-train the spam filter via a Django Admin action on the
SpamFilter
model. The precision, recall and F1 performance indicators are also shown in the admin interface.