CARVIEW |
Select Language
HTTP/2 200
date: Sat, 11 Oct 2025 16:44:02 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, X-Requested-With,Accept-Encoding, Accept, X-Requested-With
x-repository-download: git clone https://github.com/simonw/simonwillisonblog.git
etag: W/"fe587f18463004bb07085bde7e9025ea"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: no-referrer-when-downgrade
content-security-policy: default-src 'none'; base-uri 'self'; child-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com *.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com github.githubassets.com objects-origin.githubusercontent.com copilot-proxy.githubusercontent.com proxy.individual.githubcopilot.com proxy.business.githubcopilot.com proxy.enterprise.githubcopilot.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com productionresultssa0.blob.core.windows.net/ productionresultssa1.blob.core.windows.net/ productionresultssa2.blob.core.windows.net/ productionresultssa3.blob.core.windows.net/ productionresultssa4.blob.core.windows.net/ productionresultssa5.blob.core.windows.net/ productionresultssa6.blob.core.windows.net/ productionresultssa7.blob.core.windows.net/ productionresultssa8.blob.core.windows.net/ productionresultssa9.blob.core.windows.net/ productionresultssa10.blob.core.windows.net/ productionresultssa11.blob.core.windows.net/ productionresultssa12.blob.core.windows.net/ productionresultssa13.blob.core.windows.net/ productionresultssa14.blob.core.windows.net/ productionresultssa15.blob.core.windows.net/ productionresultssa16.blob.core.windows.net/ productionresultssa17.blob.core.windows.net/ productionresultssa18.blob.core.windows.net/ productionresultssa19.blob.core.windows.net/ github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com wss://alive-staging.github.com api.githubcopilot.com api.individual.githubcopilot.com api.business.githubcopilot.com api.enterprise.githubcopilot.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com copilot-workspace.githubnext.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: blob: github.githubassets.com media.githubusercontent.com camo.githubusercontent.com identicons.github.com avatars.githubusercontent.com private-avatars.githubusercontent.com github-cloud.s3.amazonaws.com objects.githubusercontent.com release-assets.githubusercontent.com secured-user-images.githubusercontent.com/ user-images.githubusercontent.com/ private-user-images.githubusercontent.com opengraph.githubassets.com marketplace-screenshots.githubusercontent.com/ copilotprodattachments.blob.core.windows.net/github-production-copilot-attachments/ github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com objects-origin.githubusercontent.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/ private-user-images.githubusercontent.com github-production-user-asset-6210df.s3.amazonaws.com gist.github.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; upgrade-insecure-requests; worker-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/
server: github.com
content-encoding: gzip
accept-ranges: bytes
set-cookie: _gh_sess=9vsXvefcelIEAmtWHmpKW46evpMiyXYDqaGjKtP5dfqq5hfpxZ%2FsaDwanUblnRQsxNNvSJnmEAIIK%2Ft5hRsWIRMbEEvvd%2B8hVNgZw0E9Pgnbe3S%2BDlU3TEKFF0Z9aXBdBOdGJSMa5GNDLrscg8Y220hdeG%2FgP%2BgBpX7zFhrpUoJQ%2BLbB0VF%2FSFDIPoYLQwH9N4DQXp8uqNhM8InqwRGIr9ipCZ2aSWrh6Axrm00bpoTvr%2BcvvwSZ3ap9WLGQJoZgsElo0X5LaVyUYnqUOc4Srg%3D%3D--5Oip%2FK4bZnZ0np%2Fl--cvFdC9R%2FRrCoen%2Bvk2F9gw%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax
set-cookie: _octo=GH1.1.1200307676.1760201041; Path=/; Domain=github.com; Expires=Sun, 11 Oct 2026 16:44:01 GMT; Secure; SameSite=Lax
set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Sun, 11 Oct 2026 16:44:01 GMT; HttpOnly; Secure; SameSite=Lax
x-github-request-id: EDE8:123F70:88FD32:B3DFEE:68EA8951
Massive clean-up of |safe, |escape and XHTML processing code · simonw/simonwillisonblog@7295cdd · GitHub
committed
Copy file name to clipboardExpand all lines: blog/templatetags/entry_tags.py
Copy file name to clipboardExpand all lines: templates/archive_month.html
Copy file name to clipboard
Copy file name to clipboardExpand all lines: templates/includes/blog_mixed_list.html
Skip to content
Navigation Menu
{{ message }}
-
-
Notifications
You must be signed in to change notification settings - Fork 26
Commit 7295cdd

Simon Willison
Massive clean-up of |safe, |escape and XHTML processing code
I think I originally wrote these templates back before Django had auto-
escaping! As a result, they were cluttered with calls to |safe and |escape and
the logic was getting pretty confusing.
I've managed to eliminate every single call to |escape and all but two
(necessary) calls to |safe.
Almost all of the content on my blog should be treated as regular strings
without markup - the the exception of the entry bodies themselves, which are
stored (and validated) as XHTML fragments.
Previously, my various template filters like |typography and |first_paragraph
would each take a string of (hopefully) XHTML, parse that into ElementTree,
process it in some way and then serialize it back to a string again. This
could happen dozens of times on a single page.
I've introduced a new XhtmlString class which allows me to execute that
parsing stage just once, and then pass an object along to each of the filters
that they can then work with. The __str__ method knows how to serialize back
to XML.
I've also introduced a |xhtml filter which expects a string of XHTML and turns
it into one of those objects, treating the markup as markup. Without this
filter, a string will be assumed to be e.g. a title with ampersands in it so
the string will be escaped before being handed to ElementTree.1 parent d6e6eeb commit 7295cddCopy full SHA for 7295cdd
File tree
Expand file treeCollapse file tree
14 files changed
+96
-64
lines changedFilter options
- blog
- templatetags
- templates
- feeds
- includes
Expand file treeCollapse file tree
14 files changed
+96
-64
lines changedCollapse file: blog/templatetags/entry_tags.py
blog/templatetags/entry_tags.py
Copy file name to clipboardExpand all lines: blog/templatetags/entry_tags.py+48-29Lines changed: 48 additions & 29 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
1 | 1 |
| |
2 | 2 |
| |
| 3 | + | |
| 4 | + | |
3 | 5 |
| |
4 | 6 |
| |
5 | 7 |
| |
| |||
8 | 10 |
| |
9 | 11 |
| |
10 | 12 |
| |
11 |
| - | |
12 |
| - | |
13 |
| - | |
14 |
| - | |
15 |
| - | |
16 |
| - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
17 | 36 |
| |
18 | 37 |
| |
19 | 38 |
| |
20 | 39 |
| |
21 | 40 |
| |
22 |
| - | |
23 |
| - | |
| 41 | + | |
| 42 | + | |
24 | 43 |
| |
25 | 44 |
| |
26 | 45 |
| |
27 | 46 |
| |
28 | 47 |
| |
29 | 48 |
| |
30 |
| - | |
| 49 | + | |
31 | 50 |
| |
32 | 51 |
| |
33 | 52 |
| |
34 | 53 |
| |
35 | 54 |
| |
36 | 55 |
| |
37 | 56 |
| |
38 |
| - | |
39 |
| - | |
| 57 | + | |
| 58 | + | |
40 | 59 |
| |
41 | 60 |
| |
42 | 61 |
| |
43 | 62 |
| |
44 |
| - | |
45 |
| - | |
| 63 | + | |
| 64 | + | |
46 | 65 |
| |
47 |
| - | |
| 66 | + | |
48 | 67 |
| |
49 |
| - | |
50 |
| - | |
| 68 | + | |
| 69 | + | |
51 | 70 |
| |
52 | 71 |
| |
53 | 72 |
| |
54 | 73 |
| |
55 |
| - | |
56 |
| - | |
| 74 | + | |
| 75 | + | |
57 | 76 |
| |
58 |
| - | |
| 77 | + | |
59 | 78 |
| |
60 |
| - | |
| 79 | + | |
61 | 80 |
| |
62 | 81 |
| |
63 | 82 |
| |
| |||
78 | 97 |
| |
79 | 98 |
| |
80 | 99 |
| |
81 |
| - | |
82 |
| - | |
| 100 | + | |
| 101 | + | |
83 | 102 |
| |
84 | 103 |
| |
85 |
| - | |
| 104 | + | |
86 | 105 |
| |
87 | 106 |
| |
88 | 107 |
| |
89 | 108 |
| |
90 | 109 |
| |
91 | 110 |
| |
92 |
| - | |
93 |
| - | |
94 |
| - | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
95 | 114 |
| |
96 | 115 |
| |
97 | 116 |
| |
| |||
126 | 145 |
| |
127 | 146 |
| |
128 | 147 |
| |
129 |
| - | |
130 |
| - | |
131 |
| - | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
132 | 151 |
| |
133 | 152 |
| |
134 | 153 |
| |
|
Collapse file: blog/tests.py
+13Lines changed: 13 additions & 0 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
42 | 42 |
| |
43 | 43 |
| |
44 | 44 |
| |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + |
Collapse file: templates/archive_day.html
+1-1Lines changed: 1 addition & 1 deletion
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
15 | 15 |
| |
16 | 16 |
| |
17 | 17 |
| |
18 |
| - | |
| 18 | + | |
19 | 19 |
| |
20 | 20 |
| |
21 | 21 |
| |
|
Collapse file: templates/archive_month.html
templates/archive_month.html
Copy file name to clipboardExpand all lines: templates/archive_month.html+1-1Lines changed: 1 addition & 1 deletion
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
10 | 10 |
| |
11 | 11 |
| |
12 | 12 |
| |
13 |
| - | |
| 13 | + | |
14 | 14 |
| |
15 | 15 |
| |
16 | 16 |
| |
|
Collapse file: templates/archive_tag.html
+2-2Lines changed: 2 additions & 2 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
1 | 1 |
| |
2 | 2 |
| |
3 |
| - | |
| 3 | + | |
4 | 4 |
| |
5 | 5 |
| |
6 |
| - | |
| 6 | + | |
7 | 7 |
| |
8 | 8 |
| |
9 | 9 |
| |
|
Collapse file: templates/blogmark.html
+3-3Lines changed: 3 additions & 3 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
1 | 1 |
| |
2 | 2 |
| |
3 |
| - | |
| 3 | + | |
4 | 4 |
| |
5 | 5 |
| |
6 |
| - | |
| 6 | + | |
7 | 7 |
| |
8 | 8 |
| |
9 | 9 |
| |
10 |
| - | |
| 10 | + | |
11 | 11 |
| |
12 | 12 |
| |
13 | 13 |
| |
|
Collapse file: templates/entry.html
+9-9Lines changed: 9 additions & 9 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
1 | 1 |
| |
2 | 2 |
| |
3 |
| - | |
| 3 | + | |
4 | 4 |
| |
5 |
| - | |
6 |
| - | |
| 5 | + | |
| 6 | + | |
7 | 7 |
| |
8 | 8 |
| |
9 |
| - | |
| 9 | + | |
10 | 10 |
| |
11 |
| - | |
| 11 | + | |
12 | 12 |
| |
13 | 13 |
| |
14 | 14 |
| |
15 | 15 |
| |
16 | 16 |
| |
17 | 17 |
| |
18 | 18 |
| |
19 |
| - | |
| 19 | + | |
20 | 20 |
| |
21 |
| - | |
| 21 | + | |
22 | 22 |
| |
23 | 23 |
| |
24 | 24 |
| |
25 |
| - | |
| 25 | + | |
26 | 26 |
| |
27 | 27 |
| |
28 |
| - | |
| 28 | + | |
29 | 29 |
| |
30 | 30 |
| |
31 | 31 |
| |
|
Collapse file: templates/feeds/quotation.html
templates/feeds/quotation.html
Copy file name to clipboard+1-1Lines changed: 1 addition & 1 deletion
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
1 |
| - | |
| 1 | + |
Collapse file: templates/homepage.html
+6-6Lines changed: 6 additions & 6 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
10 | 10 |
| |
11 | 11 |
| |
12 | 12 |
| |
13 |
| - | |
14 |
| - | |
| 13 | + | |
| 14 | + | |
15 | 15 |
| |
16 | 16 |
| |
17 | 17 |
| |
| |||
23 | 23 |
| |
24 | 24 |
| |
25 | 25 |
| |
26 |
| - | |
27 |
| - | |
| 26 | + | |
| 27 | + | |
28 | 28 |
| |
29 | 29 |
| |
30 | 30 |
| |
31 | 31 |
| |
32 |
| - | |
| 32 | + | |
33 | 33 |
| |
34 |
| - | |
| 34 | + | |
35 | 35 |
| |
36 | 36 |
| |
37 | 37 |
| |
|
Collapse file: templates/includes/blog_mixed_list.html
templates/includes/blog_mixed_list.html
Copy file name to clipboardExpand all lines: templates/includes/blog_mixed_list.html+6-6Lines changed: 6 additions & 6 deletions
Original file line number | Diff line number | Diff line change | |
---|---|---|---|
| |||
2 | 2 |
| |
3 | 3 |
| |
4 | 4 |
| |
5 |
| - | |
6 |
| - | |
| 5 | + | |
| 6 | + | |
7 | 7 |
| |
8 | 8 |
| |
9 | 9 |
| |
10 | 10 |
| |
11 | 11 |
| |
12 | 12 |
| |
13 | 13 |
| |
14 |
| - | |
| 14 | + | |
15 | 15 |
| |
16 |
| - | |
| 16 | + | |
17 | 17 |
| |
18 | 18 |
| |
19 | 19 |
| |
20 | 20 |
| |
21 | 21 |
| |
22 | 22 |
| |
23 |
| - | |
| 23 | + | |
24 | 24 |
| |
25 | 25 |
| |
26 | 26 |
| |
27 |
| - | |
| 27 | + | |
28 | 28 |
| |
29 | 29 |
| |
30 | 30 |
|
You can’t perform that action at this time.
0 commit comments