Self-hostable blog for developers built on Wagtail and Django, with webpack, Bootstrap, and CodeMirror.
blogbootstrapdjangodockerhandcodedpythonself-hostedwagtailwebpack
1from django.templatetags.static import static
2from django.utils.html import escape, format_html
3from wagtail_modeladmin.mixins import ThumbnailMixin
4from wagtail_modeladmin.options import ModelAdmin, modeladmin_register
5from wagtail import hooks
6from wagtail.rich_text import LinkHandler
7
8from pages.models import BlogPostPage
9from scheduler.models import ScheduledTask
10from mail.models import Subscriber
11
12
13# @hooks.register("insert_global_admin_js", order=100)
14# def global_admin_js():
15# return format_html('<script src="{}"></script>', static("admin.global.js"))
16
17
18@hooks.register("insert_global_admin_css", order=100)
19def global_admin_css():
20 return format_html('<link rel="stylesheet" href="{}">', static("admin.global.css"))
21
22
23@hooks.register("insert_editor_js", order=100)
24def editor_js():
25 return format_html('<script src="{}"></script>', static("admin.editor.js"))
26
27
28@hooks.register("insert_editor_css", order=100)
29def editor_css():
30 return format_html('<link rel="stylesheet" href="{}">', static("admin.editor.css"))
31
32
33class ExternalLinkHandler(LinkHandler):
34 identifier = 'external'
35
36 @classmethod
37 def expand_db_attributes(cls, attrs):
38 href = attrs["href"]
39 return '<a href="%s" target="_blank" rel="noopener noreferrer">' % escape(href)
40
41
42@hooks.register('register_rich_text_features')
43def register_external_link_handler(features):
44 features.register_link_type(ExternalLinkHandler)
45
46
47class BlogPostPageAdmin(ThumbnailMixin, ModelAdmin):
48 model = BlogPostPage
49 menu_label = 'Posts'
50 menu_icon = 'doc-full-inverse'
51 exclude_from_explorer = True
52 menu_order = 200
53 list_display = ('admin_thumb', 'title', 'first_published_at', 'tags_list', 'live')
54 list_filter = ('tags', 'live')
55 search_fields = ('title', 'body')
56 ordering = ('-first_published_at',)
57 thumb_image_field_name = 'cover_image'
58 thumb_image_width = 75
59
60 def get_queryset(self, request):
61 return super().get_queryset(request).prefetch_related('tags')
62
63 def tags_list(self, obj):
64 return ', '.join(o.name for o in obj.tags.all())
65
66
67modeladmin_register(BlogPostPageAdmin)
68
69
70class ScheduledTaskAdmin(ModelAdmin):
71 model = ScheduledTask
72 menu_label = 'Scheduler'
73 menu_icon = 'time'
74 add_to_settings_menu = True
75 menu_order = 900
76 list_display = ('management_command', 'run_interval', 'last_run_at', 'next_run_at')
77 list_filter = ('run_interval',)
78 search_fields = ('management_command',)
79 ordering = ('-run_interval',)
80
81
82modeladmin_register(ScheduledTaskAdmin)
83
84
85class SubscriberAdmin(ModelAdmin):
86 model = Subscriber
87 menu_label = 'Subscribers'
88 menu_icon = 'mail'
89 add_to_settings_menu = True
90 menu_order = 1000
91 list_display = ('email', 'created_at')
92 search_fields = ('email',)
93 ordering = ('-created_at',)
94
95
96modeladmin_register(SubscriberAdmin)