Matthias Kestenholz: Posts about Weeknoteshttps://406.ch/writing/category-weeknotes/2025-04-09T12:00:00ZMatthias KestenholzWeeknotes (2025 week 15)https://406.ch/writing/weeknotes-2025-week-15/2025-04-09T12:00:00Z2025-04-09T12:00:00Z<h1 id="weeknotes-2025-week-15"><a class="toclink" href="#weeknotes-2025-week-15">Weeknotes (2025 week 15)</a></h1>
<h2 id="djangonaut-space"><a class="toclink" href="#djangonaut-space">Djangonaut Space</a></h2>
<p>We have already reached the final week of the <a href="https://djangonaut.space/">Djangonaut
Space</a> session 4. I had a great time as a navigator
and am looking forward to participate more, but for now I’m also glad that I do
not have the additional responsibility at least for the close future.</p>
<p>We have done great work on the
<a href="https://pypi.org/project/django-debug-toolbar/">django-debug-toolbar</a> in our
group, more is to come.</p>
<h2 id="progress-on-the-prose-editor"><a class="toclink" href="#progress-on-the-prose-editor">Progress on the prose editor</a></h2>
<p>I have done much work on
<a href="https://pypi.org/project/django-prose-editor/">django-prose-editor</a> in the
last few weeks and after a large list of alphas and betas I’m nearing a state
which I want to release into the wild.</p>
<p>The integration has been completely rethought (again) and now uses JavaScript
modules and importmaps. The ground work to support all of that in Django has
been laid in <a href="https://pypi.org/project/django-js-asset/">django-js-asset</a>.</p>
<p>The nice thing about using JavaScript modules and importmaps is that we now
have an easy way to combine the power of modern JavaScript customization with
easy cache busting using Django’s <code>ManifestStaticFilesStorage</code>. A longer post
on this is brewing and I hope to have it ready soon-ish.</p>
<p>As a sneak peek, here’s the way it works:</p>
<div class="chl"><pre><span></span><code><span class="kn">from</span> <span class="nn">django_prose_editor.fields</span> <span class="kn">import</span> <span class="n">ProseEditorField</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">ProseEditorField</span><span class="p">(</span>
<span class="n">extensions</span><span class="o">=</span><span class="p">{</span>
<span class="s2">"Bold"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="s2">"Italic"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="s2">"BulletList"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="s2">"Link"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="p">},</span>
<span class="c1"># sanitize=True is the default when using extensions</span>
<span class="p">)</span>
</code></pre></div>
<p>The nice thing about it is that the sanitization allowlist for
<a href="https://github.com/messense/nh3">nh3</a> only includes tags and attributes which
are enabled via the <code>extensions</code> dict. So, you don’t have to do anything else
to be safe from XSS etc.</p>
<p>Check out the pre-releases on
<a href="https://pypi.org/project/django-prose-editor/#history">PyPI</a> or have a look at
the <a href="https://django-prose-editor.readthedocs.io/">documentation</a> to learn more
about this project!</p>
<h2 id="using-claude-code"><a class="toclink" href="#using-claude-code">Using Claude Code</a></h2>
<p>I have been using Claude Code (without editor integrations, thank you very
much) more and more. It’s a good coding companion when it comes to throwing
around ideas, drafting docs and writing unit tests including integration tests.</p>
<p>Sometimes I’m really surprised at how good it is. Other times… less so. The
tool often finds a way to get tests passing, but when the editor integration
tests directly manipulate <code>innerHTML</code> and then Claude proclaims that
interacting with the editor is now shown to work I have to chuckle a bit. And
when I insist on doing what I mean and not just finding broken workarounds it
doesn’t really change anything. After spinning more we’re always back where we
started.</p>
<p>I am somewhat glad that this is where we’re at now. I’m not 100% sure if it’s
progress. At least it’s surprisingly funny at times.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<p>I haven’t written a regular weeknotes entry since the end of January, so
naturally the list here is longer than usual.</p>
<ul>
<li><a href="https://pypi.org/project/feincms3-forms/">feincms3-forms 0.5.1</a>: I
inadvertently bumped the Django dependency without actually wanting that;
this patch release reverts that (while adding official support for new Django
and Python versions).</li>
<li><a href="https://pypi.org/project/django-mptt/">django-mptt 0.17</a>: Mariusz has done
all the hard work for supporting newer versions of Django. I just had to
press the release button. That being said, four years after marking the
package as unmaintained I’m still maintaining it. At least I don’t get
complaints anymore…</li>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor
0.4</a>: Added a dependency
on the pre-release of django-prose-editor and added a test suite including
integration tests so that we actually now when stuff breaks the next time!</li>
<li><a href="https://pypi.org/project/django-debug-toolbar/">django-debug-toolbar 5.1</a>:
See above.</li>
<li><a href="https://pypi.org/project/feincms3-data/">feincms3-data</a>: Added fixes to dump
distinct objects. Spent more time than useful on the Django change which
added a final newline to JSON-serialized data.</li>
<li><a href="https://pypi.org/project/django-js-asset/">django-js-asset 3.1.2</a>:
Importmaps support, added a <code>static_lazy</code> helper which is useful to define
module-scoped static URLs. The later wouldn’t work with the
<code>ManifestStaticFilesStorage</code> because the manifest doesn’t yet exist when
<code>collectstatic</code> runs, so the actual evaluation of static URLs has to be
postponed. The lazy version solves this nicely.</li>
<li><a href="https://pypi.org/project/feincms3-sites/">feincms3-sites 0.21.1</a> and <a href="https://pypi.org/project/feincms3-language-sites/">feincms3-language-sites 0.4.1</a>: See the relevant <a href="https://406.ch/writing/til-tools-exist-which-do-not-lowercase-domain-names-when-requesting-websites-over-http-s/">TIL</a> blogpost.</li>
</ul>Weeknotes (2025 week 05)https://406.ch/writing/weeknotes-2025-week-05/2025-01-29T12:00:00Z2025-01-29T12:00:00Z<h1 id="weeknotes-2025-week-05"><a class="toclink" href="#weeknotes-2025-week-05">Weeknotes (2025 week 05)</a></h1>
<h2 id="djangonaut-space"><a class="toclink" href="#djangonaut-space">Djangonaut Space</a></h2>
<p>In December I wrote a few paragraphs about <a href="https://406.ch/writing/weeknotes-2024-week-49/">my decision to not run for the
Django Steering Council</a>,
mentioning that I want to contribute in different ways.</p>
<p>I have offered to contribute to Djangonaut Space to do some mentoring. I’m
already a bit stressed, but that’s normal and to be expected. I’ll probably
have more to share about that in the close future!</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://github.com/feincms/feincms3-cookiecontrol/commits/main/">feincms-cookiecontrol 1.6</a>: Removed the hardcoded dependency upon <a href="https://feincms3.readthedocs.io/">feincms3</a> and some additional code golfing. The cookie banner JavaScript is now back to <4KiB.</li>
<li><a href="https://pypi.org/project/django-curtains/">django-curtains 0.7</a>: Updated the CI job list and modernized the package somewhat, no code changes necessary. It’s good to release updated versions though just to show that it’s still actively maintained.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.10.3</a>: Small CSS fixes and mainly updated TipTap/ProseMirror.</li>
<li><a href="https://pypi.org/project/django-imagefield/">django-imagefield 0.22</a>: The updated version no longer autodeletes processed images; this wasn’t really a problem before but I was a little bit fearful that images are still referenced elsewhere and this change let’s me sleep better.</li>
<li><a href="https://pypi.org/project/feincms-oembed/">feincms-oembed 2.0</a>: Oembed support for FeinCMS 1 without actually depending upon the FeinCMS package itself. Still works.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 7.2</a>: The <code>Region</code> type is now hashable; this may be useful, or not.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 5.3.1</a>: I undeprecated the <code>TemplateMixin</code> because even though <code>PageTypeMixin</code> is nicer, sometimes all you need is a template selector.</li>
</ul>Weeknotes (2025 week 03)https://406.ch/writing/weeknotes-2025-week-03/2025-01-15T12:00:00Z2025-01-15T12:00:00Z<h1 id="weeknotes-2025-week-03"><a class="toclink" href="#weeknotes-2025-week-03">Weeknotes (2025 week 03)</a></h1>
<h2 id="claude-ai-helped-me-for-the-first-time"><a class="toclink" href="#claude-ai-helped-me-for-the-first-time">Claude AI helped me for the first time</a></h2>
<p><a href="https://github.com/matthiask/django-imagefield">django-imagefield</a> prefers
processing thumbnails, cropped images etc. directly when saving the model and
not later on demand; it’s faster and also you’ll know it immediately when an
image couldn’t be processed for some reason instead of only later when people
actually try browsing your site.</p>
<p>A consequence is that if you change formats you have to remember that you have
to reprocess the images. The Django app comes with a management command
<code>./manage.py process_imagefields</code> to help with this. I have added parallel
processing based on <code>concurrent.futures</code> to it some time ago so that the
command completes faster when it is being run on a system with several cores.</p>
<p>A work colleague is using macOS (many are, in fact), and he always got
multiprocessing Python crashes. This is a well known issue and I remember
reading about it a few years ago. I checked the docs and saw that the
<a href="https://docs.python.org/3/library/concurrent.futures.html"><code>concurrent.futures</code></a>
page doesn’t mention macOS, but
<a href="https://docs.python.org/3/library/multiprocessing.html"><code>multiprocessing</code></a>
does. So, I hoped that a simple rewrite of the management command using
<code>multiprocessing</code> might fix it.</p>
<p>Because I was in a rush and really didn’t want to do it I turned to an AI
assistant for doing this boring work. To my surprise it immediately produced a
version which I could easily fix by hand to produce a working version. Of
course, the initial response was totally broken, removed code it wasn’t
supposed to, and even the syntax was invalid. I didn’t expect more though, but
what was surprising was that it actually felt like I had to do less work at
this time.</p>
<p>The assistant also helped adding a <code>--no-parallel</code> flag to the management
command. The output was even more broken than the output of the change
mentioned above, but again, I could easily fix it to achieve what I wanted.</p>
<p>The fact that I know the code and <a href="https://git-scm.com/">git</a> well certainly
helped, the assistant would really have helped without that knowledge.</p>
<p>In the end, switching to <code>multiprocessing</code> didn’t help, but adding the
<code>--no-parallel</code> flag allowed them to run the processing themselves by not
spawning any additional threads or processes.</p>
<p>The energy use and the stealing of copyrighted material done by the AI
companies is still really bad. It does feel somewhat OK to use an AI assistant
in an area where I’m proficient as well and where I probably also supplied
training material (without being asked if I wanted this) though. It’s making me
slightly faster, and doesn’t allow me to do things I really couldn’t otherwise.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/FeinCMS/">FeinCMS 24.12.3</a>: I have added a TinyMCE
7 integration to FeinCMS.</li>
<li><a href="https://pypi.org/project/django-imagefield/">django-imagefield 0.21.1</a>: See
above.</li>
</ul>Weeknotes (2024 week 51)https://406.ch/writing/weeknotes-2024-week-51/2024-12-20T12:00:00Z2024-12-20T12:00:00Z<h1 id="weeknotes-2024-week-51"><a class="toclink" href="#weeknotes-2024-week-51">Weeknotes (2024 week 51)</a></h1>
<h2 id="building-forms-using-django"><a class="toclink" href="#building-forms-using-django">Building forms using Django</a></h2>
<p>I last wrote about this topic <a href="https://406.ch/writing/building-forms-with-the-django-admin/">in April</a>. It has <a href="https://mastodon.social/@webology/113669270531953652">resurfaced on Mastodon this week</a>. I’m thinking about writing a <a href="https://github.com/feincms/feincms3-forms">feincms3-forms</a> demo app, but I already have too much on my plate. I think composing a forms builder on top of <a href="https://django-content-editor.readthedocs.io/">django-content-editor</a> is the way to go, instead of replacing the admin interface altogether – sure, you can always do that, but it’s so much less composable…</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/blacknoise/">blacknoise 1.2</a>: No real changes, added support for Python 3.13 basically without changing anything. It’s always nice when this happens.</li>
<li><a href="https://pypi.org/project/django-imagefield/">django-imagefield 0.21</a></li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.10</a>: I rebuilt django-prose-editor from the ground up <a href="https://406.ch/writing/rebuilding-django-prose-editor-from-the-ground-up/">and wrote about that two weeks ago</a>. The 0.10 release marks the final point of this particular rewrite.</li>
<li><a href="https://pypi.org/project/django-js-asset/">django-js-asset 3.0</a>: See the blog post from <a href="https://406.ch/writing/object-based-assets-for-django-s-forms-media/">this week</a></li>
</ul>Weeknotes (2024 week 49)https://406.ch/writing/weeknotes-2024-week-49/2024-12-06T12:00:00Z2024-12-06T12:00:00Z<h1 id="weeknotes-2024-week-49"><a class="toclink" href="#weeknotes-2024-week-49">Weeknotes (2024 week 49)</a></h1>
<h2 id="django-steering-council-elections"><a class="toclink" href="#django-steering-council-elections">Django Steering Council elections</a></h2>
<p>I have been thinking long and hard about running for the Django Steering Council. I think there are a few things I could contribute since I’ve been using Django for 16 or more years, and have been working on, maintaining and publishing third-party apps almost all this time. I have also contributed a few small features to Django core itself, and contributed my fair share of tests and bugfixes. The reason why I haven’t been more involved was always that I feared the review process with what I perceive to be a too unrestrained perfectionism. Teaching people is good, but I fear that those who teach are self-selected survivors of the process, which come to appreciate the perfectionism a bit too much. It’s somewhat the same as with the Swiss naturalization process – the hurdles are very high, and some of those who weather the process maybe are or grow to be too fond of it.</p>
<p>An important point is that this has nothing to do with being nice (or not). Everybody has always been great, maybe with the exception of myself back when I didn’t understand that the problem wasn’t the individuals but the way everyone has agreed things should be done.</p>
<p>I’m not the only one who thinks that we <a href="https://knowyourmeme.com/memes/we-should-improve-society-somewhat">should improve the process somewhat</a>. So, I’m definitely going to look out for candidates who think this is important.</p>
<p>There are a few reasons why I’m not running myself at this time. A somewhat important reason is that my candidacy wouldn’t help diversity at all. This shouldn’t discourage anyone else with the same background from running – we cannot change the world all at once. More importantly, I have more personal reasons for being hesitant to accept new commitments. That being said, I’m looking forward to be more involved in the community in other ways. And also, it’s not now or never.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/feincms3-cookiecontrol/">feincms3-cookiecontrol 1.5.4</a>: No functional changes, only code golfing. It’s nice to have a working cookie banner with a solution for embedding third party content only when people consent in less than 4KiB of minified (not compressed!) JavaScript.</li>
<li><a href="https://pypi.org/project/django-admin-ordering/">django-admin-ordering 0.20</a>: Objects can now be reordered using arrow buttons instead of drag drop or manually changing the ordering field’s value. This should make the package more accessible. It’s always a joy when people contribute such useful improvements.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.10a?</a>: See <a href="https://406.ch/writing/rebuilding-django-prose-editor-from-the-ground-up/">the recent blog post</a>.</li>
</ul>Weeknotes (2024 week 47)https://406.ch/writing/weeknotes-2024-week-47/2024-11-20T12:00:00Z2024-11-20T12:00:00Z<h1 id="weeknotes-2024-week-47"><a class="toclink" href="#weeknotes-2024-week-47">Weeknotes (2024 week 47)</a></h1>
<p>I missed a single co-writing session and of course that lead to four weeks of no posts at all to the blog. Oh well.</p>
<h2 id="debugging"><a class="toclink" href="#debugging">Debugging</a></h2>
<p>I want to share a few debugging stories from the last weeks.</p>
<h3 id="pillow-11-and-djangos-get_image_dimensions"><a class="toclink" href="#pillow-11-and-djangos-get_image_dimensions">Pillow 11 and Django’s <code>get_image_dimensions</code></a></h3>
<p>The goal of <a href="https://github.com/matthiask/django-imagefield">django-imagefield</a>
was to deeply verify that Django and Pillow are able to work with uploaded
files; some files can be loaded, their dimensions can be inspected, but
problems happen later when Pillow actually tries resizing or filtering files.
Because of this django-imagefield does more work when images are added to the
system instead of working around it later. (Django doesn’t do this on purpose
because doing all this work up-front could be considered a DoS factor.)</p>
<p>In the last weeks I suddenly got recurring errors from saved files again,
something which shouldn’t happen, but obviously did.</p>
<p>Django wants to read image dimensions when accessing or saving image files (by
the way, always use <code>height_field</code> and <code>width_field</code>, otherwise Django will
open and inspect image files even when you’re only loading Django models from
the database…!) and it uses a smart and wonderful<sup id="fnref:fn1"><a class="footnote-ref" href="#fn:fn1">1</a></sup> hack to do this: It reads a few hundred bytes from the image file, instructs Pillow to inspect the file and if an exception happens it reads more bytes and tries again. This process relies on the exact type of exceptions raised internally though, and the release of Pillow 11 changed the types… for some file types only. Fun times.</p>
<p>The issue had already been reported as
<a href="https://code.djangoproject.com/ticket/33240">#33240</a> and is now tracked as <a href="https://github.com/python-pillow/Pillow/issues/8530">#8530</a> on the Pillow issue tracker. Let’s see what happens.
For now, django-imagefield declares itself to be incompatible with Pillow
11.0.0 so that this error cannot happen.</p>
<h3 id="rspack-and-lightningcss-shuffled-css-properties"><a class="toclink" href="#rspack-and-lightningcss-shuffled-css-properties">rspack and lightningcss shuffled CSS properties</a></h3>
<p><a href="https://rspack.dev/">rspack</a> 1.0 started reordering CSS properties which of course lead to CSS properties overriding each other in the incorrect order. That was a fun one to debug. I tracked the issue down to the switch from the swc CSS minimizer to <a href="https://github.com/parcel-bundler/lightningcss">lightningcss</a> and submitted a reproduction to the <a href="https://github.com/parcel-bundler/lightningcss/issues/805#issuecomment-2358219597">issue tracker</a>. My rust knowledge wasn’t up to the task of attempting to submit a fix myself. Luckily, it has been fixed in the meantime.</p>
<h3 id="rspack-problems"><a class="toclink" href="#rspack-problems">rspack problems</a></h3>
<p>I have another problem with rspack where I haven’t yet tracked down the issue. rspack produces a broken bundle starting with <a href="https://github.com/web-infra-dev/rspack/releases/tag/v1.0.0-beta.2">1.0.0-beta.2</a> when compiling a particular project of mine. I have the suspicion that I have misconfigured some stuff related to import paths and yarn workspaces. I have no idea how anyone could have a complete understanding of these things…</p>
<p><strong>Update:</strong> The problem was <a href="https://github.com/web-infra-dev/rspack/issues/8027">#8027</a>, <code>experiments.css</code> is quite broken for now.</p>
<p>Bundlers are complex beasts, and I’m happy that I mostly can just use them.</p>
<h3 id="closing-thoughts"><a class="toclink" href="#closing-thoughts">Closing thoughts</a></h3>
<p>Debugging is definitely a rewarding activity for me. I like tracking stuff down like this. Unfortunately, problems always tend to crop up when time is scarce already, but what can you do.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<p>Quite a few releases, many of them verifying Python 3.13 and Django 5.1 support (if it hasn’t been added already in previous releases). The nicest part: If I remember correctly I didn’t have to change anything anywhere, everything just continues to work.</p>
<ul>
<li><a href="https://pypi.org/project/django-admin-ordering/">django-admin-ordering 0.19</a>: I added support for automatically renumbering objects on page load. This is mostly useful if you already have existing data which isn’t ordered yet.</li>
<li><a href="https://pypi.org/project/feincms3-data/">feincms3-data 0.7</a>: Made sure that objects are dumped in a deterministic order when dumping. I wanted to compare JSON dumps by hand before and after a big data migration in a customer project and differently ordered dumps made the comparison impossible.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.9</a>: I updated the ProseMirror packages, and put the editor into read-only mode for <code><textarea disabled></code> elements.</li>
<li><a href="https://pypi.org/project/feincms3-language-sites/">feincms3-language-sites 0.4</a>: Finally released the update containing the necessary hook to validate page trees and their unique paths before moving produces integrity errors. Error messages are nicer than internal server errors.</li>
<li><a href="https://pypi.org/project/django-authlib/">django-authlib 0.17.2</a>: The value of the cookie which is used to save the URL where users should be redirected to after authentication wasn’t checked for validity when setting it, only when reading it. This meant that attackers could produce invalid header errors in application servers. No real security problem here when using authlib’s code.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 5.3</a>: Minor update which mostly removes support for outdated Python and Django versions.</li>
<li><a href="https://pypi.org/project/django-imagefield/">django-imagefield 0.20</a>: See above.</li>
</ul>
<div class="footnote">
<hr />
<ol>
<li id="fn:fn1">
<p>wonderfully ugly <a class="footnote-backref" href="#fnref:fn1" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>Weeknotes (2024 week 43)https://406.ch/writing/weeknotes-2024-week-43/2024-10-23T12:00:00Z2024-10-23T12:00:00Z<h1 id="weeknotes-2024-week-43"><a class="toclink" href="#weeknotes-2024-week-43">Weeknotes (2024 week 43)</a></h1>
<p>I had some much needed time off, so this post isn’t that long even though <a href="https://406.ch/writing/weeknotes-2024-week-39/">four weeks have passed since the last entry</a>.</p>
<h2 id="from-webpack-to-rspack"><a class="toclink" href="#from-webpack-to-rspack">From webpack to rspack</a></h2>
<p>I’ve been really happy with <a href="https://rspack.dev/">rspack</a> lately. Converting
webpack projects to rspack is straightforward since it mostly supports the same
configuration, but it’s much much faster since it’s written in Rust. Rewriting
things in Rust is a recurring theme, but in this case it really helps a lot.
Building the frontend of a larger project of ours consisting of several admin
tools and complete frontend implementations for different teaching materials
only takes 10 seconds now instead of several minutes. That’s a big and relevant
difference.</p>
<p>Newcomers should probably still either use <a href="https://rsbuild.dev/">rsbuild</a>,
<a href="https://vite.dev/">Vite</a> or maybe no bundler at all. Vanilla JS and browser
support for ES modules is great. That being said, I like cache busting,
optimized bundling and far-future expiry headers in production and hot module
reloading in development a lot, so learning to work with a frontend bundler is
definitely still worth it.</p>
<h2 id="dark-mode-and-light-mode"><a class="toclink" href="#dark-mode-and-light-mode">Dark mode and light mode</a></h2>
<p>I have been switching themes in my preferred a few times per year in the past. The following ugly bit of vimscript helps switch me the theme each time the sun comes out when working outside:</p>
<div class="chl"><pre><span></span><code><span class="nv">let</span><span class="w"> </span><span class="nv">t</span>:<span class="nv">light</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span>
<span class="nv">function</span><span class="o">!</span><span class="w"> </span><span class="nv">FiatLux</span><span class="ss">()</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nv">t</span>:<span class="nv">light</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span>:<span class="nv">set</span><span class="w"> </span><span class="nv">background</span><span class="o">=</span><span class="nv">light</span>
<span class="w"> </span><span class="nv">let</span><span class="w"> </span><span class="nv">t</span>:<span class="nv">light</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="k">else</span>
<span class="w"> </span>:<span class="nv">set</span><span class="w"> </span><span class="nv">background</span><span class="o">=</span><span class="nv">dark</span>
<span class="w"> </span><span class="nv">let</span><span class="w"> </span><span class="nv">t</span>:<span class="nv">light</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span>
<span class="w"> </span><span class="k">endif</span>
<span class="nv">endfunction</span>
<span class="nv">nnoremap</span><span class="w"> </span><span class="o"><</span><span class="nv">F12</span><span class="o">></span><span class="w"> </span>:<span class="k">call</span><span class="w"> </span><span class="nl">FiatLux</span><span class="ss">()</span><span class="o"><</span><span class="nv">CR</span><span class="o">></span>
</code></pre></div>
<p>I’m using the <a href="https://devsuite.app/ptyxis/">Ptyxis</a> terminal emulator
currently, I haven’t investigated yet if there’s a shortcut to toggle dark and
light mode for it as well. Using F10 to open the main menu works fine though,
and using the mouse wouldn’t be painful either.</p>
<h2 id="helping-out-in-the-django-forum-and-the-discord"><a class="toclink" href="#helping-out-in-the-django-forum-and-the-discord">Helping out in the Django forum and the Discord</a></h2>
<p>I have found some pleasure in helping out in the <a href="https://forum.djangoproject.com/">Django
Forum</a> and in the official <a href="https://discord.gg/xcRH6mN4fa">Django
Discord</a>. I sometimes wonder why more people
aren’t reading the Django source code when they hit something which looks like
a bug or something which they do not understand. I find Django’s source code
very readable and I have found many nuggets within it. I’d always recommend
checking the documentation or maybe official help channels first, but the code
is also out there and that fact should be taken advantage of.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 7.1</a>:
Fixed a bug where the ordering and region fields were handled incorrectly
when they appear on one line in the fieldset. Also improved the presentation
of inlines in unknown regions and clarified the meaning of the move to region
dropdown. Also, released the improvements from previous patch releases as a
new minor release because that’s what I should have been doing all along.</li>
<li><a href="https://pypi.org/project/form-designer/">form-designer 0.27</a>: A user has
been bitten by <code>slugify</code> removing cyrillic characters because it only keeps
ASCII characters around. Here’s the wontfixed bug in the Django issue
tracker: <a href="https://code.djangoproject.com/ticket/8391">#8391</a>. I fixed the
issue by removing the slugification (is that even a word?) when generating
choices.</li>
</ul>Weeknotes (2024 week 39)https://406.ch/writing/weeknotes-2024-week-39/2024-09-25T12:00:00Z2024-09-25T12:00:00Z<h1 id="weeknotes-2024-week-39"><a class="toclink" href="#weeknotes-2024-week-39">Weeknotes (2024 week 39)</a></h1>
<h2 id="css-for-django-forms"><a class="toclink" href="#css-for-django-forms">CSS for Django forms</a></h2>
<p>Not much going on in OSS land. I have been somewhat active in the official
Django forum, discussing ways to add Python-level hooks to allow adding CSS
classes around form fields and their labels. The discussion on the
<a href="https://forum.djangoproject.com/t/proposal-make-it-easy-to-add-css-classes-to-a-boundfield/32022">forum</a>
and on the <a href="https://github.com/django/django/pull/18266">pull request</a> goes in
the direction of allowing using custom <code>BoundField</code> classes per form or even
per project (instead of only per field as is already possible today). This
would allow overriding <code>css_classes</code>, e.g. to add a simple <code>class="field"</code>.
Together with <code>:has()</code> this would probably allow me to skip using custom HTML
templates in 99% of all cases.</p>
<p>I have also been lurking in the Discord, but more to help and less to promote
my packages and ideas :-)</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django_user_messages/">django-user-messages 1.1</a>:
Added Django 5.0, 5.1 to the CI, and fixed the migrations to no longer
mention <code>index_together</code> at all. It seems that squashing the migrations
wasn’t sufficient, I also had to actually delete the old migrations.</li>
<li><a href="https://pypi.org/project/blacknoise/">blacknoise 1.1</a>:
<a href="https://www.starlette.io/">Starlette</a>’s <code>FileResponse</code> has gained support
for the HTTP Range header, allowing me to remove my homegrown implementation
from the package. The blacknoise implementation is now half as long as it was
in 1.0.</li>
<li><a href="https://pypi.org/project/django_fhadmin/">django-fhadmin 2.3</a>: No new
features, only tweaks to the styling and behavior prompted by updates to
Django’s admin interface.</li>
<li><a href="https://pypi.org/project/django-cabinet/">django-cabinet 0.17</a>: I have
pruned the CI matrix and accepted a pull request adding a ru translation. I
feel conflicted about that since I strongly believe that everything is
political, but I don’t know if rejecting translations helps anyone.</li>
</ul>Weeknotes (2024 week 37)https://406.ch/writing/weeknotes-2024-week-37/2024-09-11T12:00:00Z2024-09-11T12:00:00Z<h1 id="weeknotes-2024-week-37"><a class="toclink" href="#weeknotes-2024-week-37">Weeknotes (2024 week 37)</a></h1>
<h2 id="django-debug-toolbar-alpha-with-async-support"><a class="toclink" href="#django-debug-toolbar-alpha-with-async-support">django-debug-toolbar alpha with async support!</a></h2>
<p>I have helped mentoring Aman Pandey who has worked all summer to add async
support to
<a href="https://github.com/jazzband/django-debug-toolbar/">django-debug-toolbar</a>.
<a href="https://github.com/tim-schilling">Tim</a> has released an alpha which contains
all of the work up to a few days ago. Test it! Let’s find the breakages before
the final release.</p>
<h2 id="dropping-python-39-from-my-projects"><a class="toclink" href="#dropping-python-39-from-my-projects">Dropping Python 3.9 from my projects</a></h2>
<p>I have read <a href="https://noumenal.es/posts/the-only-green-python/yLw/">Carlton’s post about the only green Python release</a> and have started dropping Python 3.9 support from many of the packages I maintain. This is such a good point:</p>
<blockquote>
<p>[…] I’m also thinking about it in terms of reducing the number of Python versions we support in CI. It feels like a lot of trees to support 5 full versions of Python for their entire life. 🌳</p>
</blockquote>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-debug-toolbar/5.0.0a0/">django-debug-toolbar 5.0.0a0</a>: See above.</li>
<li><a href="https://pypi.org/project/form-designer/">form-designer 0.26.2</a>: The values
of choice fields are now returned as-is when sending mails or exporting form
submissions instead of only returning the slugified version.</li>
<li><a href="https://pypi.org/project/django-authlib/">django-authlib 0.17.1</a>: The
<a href="https://406.ch/writing/keep-content-managers-admin-access-up-to-date-with-role-based-permissions/">role-based permissions
backend</a>
had a bug where it wouldn’t return all available permissions in all
circumstances, leading to empty navigation sidebars in the Django
administration. This has been fixed.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 5.2.3</a>: Bugfix release, the
page moving interface is no longer hidden by an expanded navigation sidebar.
I almost always turn off the sidebar in my projects so I haven’t noticed
this.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.8.1</a>:
Contains the most recent ProseMirror updates and bugfixes.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor
7.0.10</a>: Now supports
sections. Separate blog post coming up!</li>
</ul>Weeknotes (2024 week 35)https://406.ch/writing/weeknotes-2024-week-35/2024-08-28T12:00:00Z2024-08-28T12:00:00Z<h1 id="weeknotes-2024-week-35"><a class="toclink" href="#weeknotes-2024-week-35">Weeknotes (2024 week 35)</a></h1>
<h2 id="getting-deep-into-htmx-and-django-template-partials"><a class="toclink" href="#getting-deep-into-htmx-and-django-template-partials">Getting deep into htmx and django-template-partials</a></h2>
<p>I have been skeptical about <a href="https://htmx.org/">htmx</a> for some time because basically everything the library does is straightforward to do myself with a few lines of JavaScript. I am a convert now because, really, adding a few HTML attributes is nicer than copy pasting a few lines of JavaScript. Feels good.</p>
<p>The combination of htmx with <a href="https://github.com/carltongibson/django-template-partials/">django-template-partials</a> is great as well. I didn’t know I had been missing template partials until I started using them. Includes are still useful, but replacing some of them with partials makes working on the project much more enjoyable.</p>
<p>I haven’t yet had a use for <a href="https://django-htmx.readthedocs.io/">django-htmx</a> but I may yet surprise myself.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-authlib/">django-authlib 0.17</a>: django-authlib bundles <code>authlib.little_auth</code> which offers an user model which uses the email address as the username. I have also introduced the concept of <a href="https://406.ch/writing/keep-content-managers-admin-access-up-to-date-with-role-based-permissions/">roles instead of permissions</a>; now I have reorganized the user admin fieldset to hide user permissions altogether. Group permissions are still available as are roles. I’m personally convinced that user permissions were a mistake.</li>
<li><a href="https://pypi.org/project/feincms3-forms/">feincms3-forms 0.5</a>: Allowed setting a maximum length for the bundled URL and email fields through the Django administration interface.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 7.0.7</a>: Fixed a bug where plugins with several fieldsets weren’t collapsed completely.</li>
<li><a href="https://pypi.org/project/django-imagefield/">django-imagefield 0.19.1</a>: Allowed deactivating autogeneration of thumbnails completely through the <code>IMAGEFIELD_AUTOGENERATE</code> setting. This is very useful for batch processing. Also, documented all available settings.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.8</a>: Added support for translating the interface elements and for restricting the available heading levels in the UI.</li>
<li><a href="https://pypi.org/project/form-designer/">form-designer 0.25</a>: Fixed the type of the author field for the send-to-author processing action.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 5.2.2</a>: Added support for embedding <a href="https://www.srf.ch/play/tv">SRF play</a> external content. They do not support oEmbed unfortunately.</li>
<li><a href="https://pypi.org/project/feincms3-cookiecontrol/">feincms3-cookiecontrol 1.5.3</a>: Added support for SRF play embeddings as well. The difference is that the feincms3-cookiecontrol embedding requires consent before embedding external content.</li>
</ul>Weeknotes (2024 week 33)https://406.ch/writing/weeknotes-2024-week-33/2024-08-14T12:00:00Z2024-08-14T12:00:00Z<h1 id="weeknotes-2024-week-33"><a class="toclink" href="#weeknotes-2024-week-33">Weeknotes (2024 week 33)</a></h1>
<h2 id="partying"><a class="toclink" href="#partying">Partying</a></h2>
<p>It’s summer, it’s hot, and it’s dance week. <a href="https://lethargy.ch/">Lethargy</a> is over, <a href="https://www.junglestreetgroove.ch/">Jungle Street Groove</a> is coming up. Good times.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor 0.1</a>: I have finally left the alpha versioning. I’m still not committing to backwards compatibility, but I have started writing a CHANGELOG.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.7.1</a>: Thanks to Carlton’s pull request I have finally cleaned up the CSS somewhat and made overriding the styles more agreeable when using the editor outside the Django administration. The confusing active state of menubar buttons has also been rectified. <a href="https://django-prose-editor.readthedocs.io/">Docs are now available on Read the Docs.</a></li>
<li><a href="https://pypi.org/project/django-imagefield/">django-imagefield 0.19</a>: django-imagefield can now be used with proxy models. Previously, thumbnails weren’t generated or deleted when saving proxy models because the signal handlers would only be called if the <code>sender</code> matches exactly. I have already debugged this before, but have forgotten about it again. The ticket is really old for this, and fixing it isn’t easy since it’s unclear what should happen (<a href="https://code.djangoproject.com/ticket/9318">#9318</a>).</li>
<li><a href="https://pypi.org/project/django_canonical_domain/">django-canonical-domain 0.11</a>: django-canonical-domain has gained support for excluding additional domains from the canonical domain redirect. django-canonical-domain is used to redirect users to HTTPS (optionally) and to a particular canonical domain (as the name says). But sometimes you have auxiliary domains, e.g. for an API service, which shouldn’t be redirected. The package can now be used in these scenarios as well.</li>
<li><a href="https://pypi.org/project/FeinCMS/">FeinCMS 24.8.2</a>: The venerable FeinCMS, now more than 15 years old. The thumbnailing support had a bug where it tried saving JPEGs using RGBA (which obviously doesn’t work). This has been fixed.</li>
</ul>Weeknotes (2024 week 31)https://406.ch/writing/weeknotes-2024-week-31/2024-07-31T12:00:00Z2024-07-31T12:00:00Z<h1 id="weeknotes-2024-week-31"><a class="toclink" href="#weeknotes-2024-week-31">Weeknotes (2024 week 31)</a></h1>
<p>I have missed almost two months of weeknotes. I’ve got some catching up to do.
I have tried writing a larger piece on my thoughts about CMS, but with
everything going on in my personal and work life I haven’t made much progress.</p>
<p>This weeknotes entry is me trying to get back into the groove of writing (and
publishing!) regularly.</p>
<h2 id="django-prose-editor"><a class="toclink" href="#django-prose-editor"><a href="https://github.com/matthiask/django-prose-editor/">django-prose-editor</a></a></h2>
<p>I have previously written about the
<a href="https://prosemirror.net/">ProseMirror</a>-based editor for Django websites
<a href="https://406.ch/writing/django-prose-editor-prose-editing-component-for-the-django-admin/">here</a>.
I have continued working on the project in the meantime. Apart from bugfixes
the big new feature is the support for showing typographic characters. For now
the editor supports showing non-breaking spaces and soft hyphens. The project
seems to get a little more interest after the deprecation of django-ckeditor
has become more well known and the project has even received a contribution by
someone else. It’s always a lovely moment when this happens.</p>
<h2 id="django-json-schema-editor"><a class="toclink" href="#django-json-schema-editor"><a href="https://github.com/matthiask/django-json-schema-editor">django-json-schema-editor</a></a></h2>
<p>Still alpha. Updated the vendorized JSON editor and fixed the integration into
Django to not throw errors with the newer version.</p>
<p>Foreign key fields now support describing the referenced value similar to the
raw ID fields functionality. Added optional support for using <code>"format":
"prose"</code> to use the django-prose-editor to edit individual fields. JSON
plugins for the content editor are now downcasted into their proxy models
automatically. This is especially useful with the feincms3 changes mentioned
below. (You do not have to use either django-content-editor or feincms3 to use
this package!)</p>
<p>The following screenshot shows the prose editor integration; the mentioned
foreign key field description isn’t visible yet here.</p>
<p><img alt="A screenshot of the JSON editor including the prose editor" src="https://406.ch/assets/20240731-json-editor.png" /></p>
<h2 id="traduire"><a class="toclink" href="#traduire"><a href="https://github.com/matthiask/traduire">Traduire</a></a></h2>
<p>Traduire (french for «translate») is a web-based platform for editing gettext
translations.</p>
<p>It is intended as a replacement for Transifex, Weblate and comparable products.
It is geared towards small teams or agencies which want to allow their
customers and their less technical team members to update translations.</p>
<p>Traduire profits from the great work done on
<a href="https://github.com/mbi/django-rosetta/">django-rosetta</a>. I would still be
using Rosetta if it would work when used with a container orchestator such as
Kubernetes. Since all application storage is ephemeral that doesn’t work,
translation editing and deployment have to be separated.</p>
<p><img alt="A screenshot of the Traduire interface" src="https://406.ch/assets/20240731-traduire.png" /></p>
<p>It is built using Django and relies on <a href="https://pypi.org/project/polib/">polib</a>
to do the heavy lifting.</p>
<p>This is a project which might also be interesting for others. I would
especially appreciate it if someone could contribute an easier way to get it up
and running, e.g. using a Docker Compose configuration or something. I am using
Kubernetes and GitOps to host it, but that’s not straightforward at all.
Really, all that’s needed to run it is a Django host with any database which is
supported by Django. I prefer using PostgreSQL because I have it, but sqlite
etc. work just as well.</p>
<h2 id="releases-since-the-second-week-of-june"><a class="toclink" href="#releases-since-the-second-week-of-june">Releases since the second week of June</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-translated-fields/">django-translated-fields 0.13</a>:
Nothing much except for CI and pre-commit updates. The implementation
continues to be rock-solid and basically unchanged.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 7.0.6</a>:
Tweaks and fixes to the new interface. Added better scrolling behavior when
dragging content around. The editor now also supports colorized icons which
helps quickly understanding the structure of some content when there are many
plugins.</li>
<li><a href="https://pypi.org/project/blacknoise/">blacknoise 1.0.2</a>:
Fixed a few bugs in the <code>blacknoise.compress</code> utility and started running
the testsuite on GitHub actions.
<a href="https://github.com/evansd/whitenoise/">whitenoise</a> has been friendly-forked
as <a href="https://github.com/Archmonger/ServeStatic">ServeStatic</a> and I’m
definitely having a close look at this project as well, but blacknoise is
simple and works well, so I’m not convinced that switching back to the much
larger project (in terms of amounts of code) is an improvement now.</li>
<li><a href="https://pypi.org/project/django-authlib/">django-authlib</a>:
Minor bugfixes.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3</a>:
Allowed registering plugin models with the renderer which aren’t supposed to
be fetched from the database. This is especially useful when used together
with JSON plugins, where the individual JSON plugins are created as proxies
for the underlying Django model and fetched all at once. Disabled the version
check on our CKEditor plugin. Still, really stop using CKEditor 4 if you want
to use maintained software.</li>
<li><a href="https://pypi.org/project/FeinCMS/">FeinCMS 24.7.1</a>:
Small bugfixes, and made the Read the Docs build work correctly.</li>
<li><a href="https://pypi.org/project/django-debug-toolbar/">django-debug-toolbar 4.4.x</a>:
The toolbar continues to be a nice project to work on. Fixed a few edge cases
in the new alerts panel.</li>
<li><a href="https://pypi.org/project/django-admin-ordering/">django-admin-ordering 0.18.2</a>:
The value of <code>ordering_field</code> now has additional sanity checks.</li>
<li><a href="https://pypi.org/project/django-cabinet/">django-cabinet 0.16</a>:
cabinet now supports exporting a folder as a ZIP file while preserving the
structure you see in the CMS instead of the structure on the file system. The
inline upload form has been dropped from the <code>CabinetForeignKey</code> widget
because the folder dropdown slowed down the page a lot when used on a site
with many folders. Using the raw ID fields popup isn’t that bad.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.6.2</a>:
See above.</li>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor 0.0.28</a>:
See above.</li>
</ul>Weeknotes (2024 week 23)https://406.ch/writing/weeknotes-2024-week-23/2024-06-07T12:00:00Z2024-06-07T12:00:00Z<h1 id="weeknotes-2024-week-23"><a class="toclink" href="#weeknotes-2024-week-23">Weeknotes (2024 week 23)</a></h1>
<h2 id="switching-everything-from-pip-to-uv"><a class="toclink" href="#switching-everything-from-pip-to-uv">Switching everything from pip to uv</a></h2>
<p>Enough said. I’m always astonished how fast computers can be.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-admin-ordering/">django-admin-ordering
0.18</a>: Added a database
index to the ordering field since we’re always sorting by it.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.4</a>:
Dropped the jQuery dependency making it possible to use the editor outside
the Django administration interface without annoying JavaScript errors.
Allowed additional heading levels and moved the block type buttons into a
popover.</li>
<li><a href="https://pypi.org/project/django-debug-toolbar/">django-debug-toolbar 4.4.2</a>:
I enjoy working on this important piece of software very much.</li>
<li><a href="https://pypi.org/project/django-email-hosts/">django-email-hosts 0.2.1</a>:
Added a command analogous to <code>./manage.py sendtestemail</code> so that it’s
possible to easily test the different configured email backends.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 5.0</a>: I completely reworked the
move node action; previously it opened a new page where you could see all
possible targets; now you can cut a page and paste it somewhere else. The
advantages of the new interface is that you don’t leave the changelist and
can still profit from all its features while moving pages around.</li>
<li><a href="https://pypi.org/project/feincms3-sites/">feincms3-sites 0.21</a>: A new
release taking advantage of a new hook in feincms3 7.0 so that the new moving
interface works.</li>
<li><a href="https://pypi.org/project/django-authlib/">django-authlib 0.16.5</a>: authlib
now shows a welcome message when authenticating using admin OAuth2. It’s nice
and helps with debugging strange authentication failures.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 7.0</a>:
I reworked the UI. The sidebar is gone, instead there are nice buttons in the
place where you can add new plugins; the plugins appear in a nice grid
instead of a list, which looks much better once you have more than just a few
plugin types available. Also, plugin type icons are now shown in the plugin
forms. I think it looks much better than before.</li>
<li><a href="https://pypi.org/project/feincms3-cookiecontrol/">feincms3-cookiecontrol
1.5.2</a>: I didn’t contribute
anything to this release which is also a nice experience for a change. The
Google consent mode integration has been improved and simplified.</li>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor
0.0.22</a>: Various
small-ish improvements. I should really start using higher version numbers,
but not having to commit to anything also feels great. That being said, the
editor is in active use in several projects, so maybe I’m deceiving myself.</li>
</ul>Weeknotes (2024 week 21)https://406.ch/writing/weeknotes-2024-week-21/2024-05-22T12:00:00Z2024-05-22T12:00:00Z<h1 id="weeknotes-2024-week-21"><a class="toclink" href="#weeknotes-2024-week-21">Weeknotes (2024 week 21)</a></h1>
<p>There have been times when work has been more enjoyable than in the last few
weeks. It feels more stressful than at other times, and this mostly has to do
with particular projects. I hope I’ll be able to move on soon.</p>
<h2 id="blacknoise"><a class="toclink" href="#blacknoise">blacknoise</a></h2>
<p>I have released <a href="https://pypi.org/project/blacknoise/">blacknoise 1.0</a>. It’s an
ASGI app for static file serving inspired by
<a href="https://github.com/evansd/whitenoise/">whitenoise</a>.</p>
<p>The 1.0 version number is only a big step in versioning terms, not much has
happened with the code. It’s a tiny little well working piece of software which
has been running in production for some time without any hickups. The biggest
recent change is that I have parallelized the gzip and brotli compression step;
this makes building images using whitenoise more painful because there the wait
is really really long sometimes. <a href="https://github.com/evansd/whitenoise/pull/484">A pull request fixing this
exists</a>, but it hasn’t moved
forwards in months.</p>
<p>I have written a longer post about it earlier this year
<a href="https://406.ch/writing/blacknoise-asgi-app-for-static-file-serving/">here</a>.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/feincms3-cookiecontrol/">feincms3-cookiecontrol 1.5</a>: Code golfing. Added backwards compatibility with old Django versions so that I can use it for old projects. Also includes optional support for Google consent management.</li>
<li><a href="https://pypi.org/project/django_fast_export/">django-fast-export 0.1.1</a>: This is basically a repackaging of the streaming CSV view from Django’s documentation as a reusable class. I have switched to using an iterator so that I can export even larger datasets.</li>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor 0.0.18</a>: Still alpha versioned but used in production in various projects. I should really release an 1.0 version, but there are no integration tests at all. Mainly visual tweaks in this update.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 6.5</a>: Better handling of templates and regions when a particular editor instance only shows a subset of configured templates. Disallowed adding plugins when in an unknown region. It’s funny how many edge cases exist in software as old as this.</li>
<li><a href="https://pypi.org/project/blacknoise/">blacknoise 1.0</a>: See above.</li>
<li><a href="https://pypi.org/project/html-sanitizer/">html-sanitizer 2.4.4</a>: Fixed edge cases with whitespace handling when merging elements.</li>
<li><a href="https://pypi.org/project/feincms3-data/">feincms3-data 0.6.1</a>: Allowed <code>./manage.py f3loaddata -</code> to load JSON data from stdin.</li>
</ul>Weeknotes (2024 week 18)https://406.ch/writing/weeknotes-2024-week-18/2024-05-03T12:00:00Z2024-05-03T12:00:00Z<h1 id="weeknotes-2024-week-18"><a class="toclink" href="#weeknotes-2024-week-18">Weeknotes (2024 week 18)</a></h1>
<h2 id="google-summer-of-code-has-begun"><a class="toclink" href="#google-summer-of-code-has-begun">Google Summer of Code has begun</a></h2>
<p>We have a student helping out with adding async support to the <a href="https://github.com/jazzband/django-debug-toolbar/">Django Debug
Toolbar</a>. It’s great that
someone can spend some concentrated time to work on this. Tim and others have
done all the necessary preparation work, I’m only helping from the sidelines so
don’t thank me.</p>
<h2 id="bike-to-work"><a class="toclink" href="#bike-to-work">Bike to Work</a></h2>
<p>Two teams from my company are participating in the <a href="https://www.biketowork.ch/">Bike to Work Challenge
2024</a>. It’s what I do anyway (if I’m not working
from home) but maybe it helps build others some motivation to get on the
bicycle once more. Public transports in the city where I live are great but
I’ll always take the bike when I can. I also went on my first mountain bike
ride in a few months yesterday, good fun.</p>
<h2 id="json-blobs-and-referential-integrity"><a class="toclink" href="#json-blobs-and-referential-integrity">JSON blobs and referential integrity</a></h2>
<p>The <a href="https://github.com/matthiask/django-json-schema-editor/">django-json-schema-editor</a> has gained support for referencing Django models. Here’s an example schema excerpt:</p>
<div class="chl"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="o">...</span>
<span class="w"> </span><span class="s">"articles"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"type"</span><span class="p">:</span><span class="w"> </span><span class="s">"array"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"format"</span><span class="p">:</span><span class="w"> </span><span class="s">"table"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"title"</span><span class="p">:</span><span class="w"> </span><span class="nx">_</span><span class="p">(</span><span class="s">"articles"</span><span class="p">),</span>
<span class="w"> </span><span class="s">"minItems"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
<span class="w"> </span><span class="s">"maxItems"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span>
<span class="w"> </span><span class="s">"items"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"type"</span><span class="p">:</span><span class="w"> </span><span class="s">"string"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"title"</span><span class="p">:</span><span class="w"> </span><span class="nx">_</span><span class="p">(</span><span class="s">"article"</span><span class="p">),</span>
<span class="w"> </span><span class="s">"format"</span><span class="p">:</span><span class="w"> </span><span class="s">"foreign_key"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"options"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"url"</span><span class="p">:</span><span class="w"> </span><span class="s">"/admin/articles/article/?_popup=1&_to_field=id"</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="o">...</span>
<span class="p">}</span>
</code></pre></div>
<p>The ID field is stringly typed; using an integer directly wouldn’t work because
the empty string isn’t a valid integer.</p>
<p>The problem with referencing models in this way is that there’s no way to know
if the referenced object is still around or not, or even to protect it against
deletion. The bundled django-content-editor <code>JSONPlugin</code> now supports
automatically generating a <code>ManyToManyField</code> with a <code>through</code> model which
protects articles from deletion as long as they are referenced from a
<code>JSONPlugin</code> instance. The <code>register_reference</code> line creates the mentioned
model with an <code>on_delete=models.PROTECT</code> foreign key to articles and a
<code>post_save</code> handler which updates said references.</p>
<div class="chl"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">django_json_schema_editor.plugins</span><span class="w"> </span><span class="kn">import</span><span class="w"> </span><span class="n">JSONPluginBase</span><span class="p">,</span><span class="w"> </span><span class="n">register_reference</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">articles.models</span><span class="w"> </span><span class="kn">import</span><span class="w"> </span><span class="n">Article</span>
<span class="k">class</span><span class="w"> </span><span class="nc">JSONPlugin</span><span class="p">(</span><span class="n">JSONPluginBase</span><span class="p">,</span><span class="w"> </span><span class="o">...</span><span class="p">):</span>
<span class="w"> </span><span class="k">pass</span>
<span class="n">register_reference</span><span class="p">(</span><span class="n">JSONPlugin</span><span class="p">,</span><span class="w"> </span><span class="s2">"articles"</span><span class="p">,</span><span class="w"> </span><span class="n">Article</span><span class="p">)</span>
</code></pre></div>
<h2 id="releases-since-the-beginning-of-april"><a class="toclink" href="#releases-since-the-beginning-of-april">Releases since the beginning of April</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor 0.0.14</a>: See above. Also, some styling work and a patch update to the vendorized json-editor.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 6.4.6</a>: Many small stylistic fixes. The target indicator when dragging plugins is now also shown when plugins are collapsed. It’s now possible to directly drag a plugin to the end, and not just to the second to last position.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.3.4</a>: Switched to the nh3 sanitizer because it’s faster and because ProseMirror never emits HTML which has to be cleaned up first. Stopped generating menu items for nodes and marks which aren’t in the schema. Added the possibility to reduce the functionality per editor instance. Small tweaks and fixes.</li>
<li><a href="https://pypi.org/project/django-tree-queries/">django-tree-queries 0.19</a>: Added support for pre-filtering the tree (much more efficient when only querying a part of the tree). Added support for adding additional fields to the CTE so that you can collect values from ancestors for other fields than the default fields too.</li>
<li><a href="https://pypi.org/project/FeinCMS/">FeinCMS 24.4.2</a>: Added support for webp images. Fixed a few of the admin list filters to work with Django 5.</li>
<li><a href="https://pypi.org/project/django-cabinet/">django-cabinet 0.14.3</a>: Fixed the support for the <code>extra_context</code> argument to our <code>changelist_view</code> implementation.</li>
</ul>Weeknotes (2024 week 14)https://406.ch/writing/weeknotes-2024-week-14/2024-04-06T12:00:00Z2024-04-06T12:00:00Z<h1 id="weeknotes-2024-week-14"><a class="toclink" href="#weeknotes-2024-week-14">Weeknotes (2024 week 14)</a></h1>
<p>I’m having a bit of a slow week with the easter weekend and a wisdom tooth
extraction. I’m recovering quite quickly it seems and I’m glad about it.</p>
<p>This weeknotes entry is short and quick. I’m trying to get back into the habit
of writing them after a mediocre start this year.</p>
<h2 id="20th-anniversary-celebration-of-young-greens-switzerland"><a class="toclink" href="#20th-anniversary-celebration-of-young-greens-switzerland">20th Anniversary Celebration of Young Greens Switzerland</a></h2>
<p>I have attended the celebration of Young Greens Switzerland. I have been a
founding member and have been active for close to ten years. A lot of time has
passed since then. It has been great to reminisce about old times with friends
and, more importantly, to see how the torch is carried on.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/blacknoise/">blacknoise 0.0.5</a>: blacknoise is an
ASGI app for static file serving inspired by
<a href="https://whitenoise.readthedocs.io/en/latest/">whitenoise</a>. It only supports
a very limited subset of whitenoise’s functionality, but it supports async.</li>
<li><a href="https://pypi.org/project/html-sanitizer/">html-sanitizer 2.4.1</a>: The lxml
library moved the HTML cleaner into its own package,
<a href="https://pypi.org/project/lxml-html-clean/">lxml-html-clean</a>; this release
adds support for that. I didn’t know that the HTML cleaner is viewed as being
problematic by the lxml maintainers. I’m having another look at
<a href="https://github.com/messense/nh3">nh3</a> and will maybe switch html-sanitizer’s
guts from lxml to nh3 in the future.</li>
<li><a href="https://pypi.org/project/django-tree-queries/">django-tree-queries 0.18</a>:
django-tree-queries now supports ordering siblings by multiple fields and
even allows descending orderings.</li>
<li><a href="https://pypi.org/project/django-cabinet/">django-cabinet 0.14.2</a>: This
release fixes the CKEditor 4 filebrowser popup when using Django 5 or better.</li>
</ul>Weeknotes (2024 week 11)https://406.ch/writing/weeknotes-2024-week-11/2024-03-16T12:00:00Z2024-03-16T12:00:00Z<h1 id="weeknotes-2024-week-11"><a class="toclink" href="#weeknotes-2024-week-11">Weeknotes (2024 week 11)</a></h1>
<h2 id="estimates"><a class="toclink" href="#estimates">Estimates</a></h2>
<p><a href="https://jacobian.org/2024/mar/11/breaking-down-tasks/">Jacob wrote an excellent post on breaking down tasks</a>. I did like the post a lot. Maybe I’ll write a longer reply later, but for now just this. <a href="https://hachyderm.io/@jacob@jacobian.org/112081126379604868">There definitely are good reasons for the pushback against estimation</a>, and it’s really not just that some people lack professionalism.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/django-cabinet/">django-cabinet 0.14.1</a>: Mini
release containing a Turkish translation. It’s always nice if software is
used.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 4.6</a>: Fixed a bug where the
move form wouldn’t use a potentially overridden <code>ModelAdmin.get_queryset</code>
method.</li>
<li><a href="https://pypi.org/project/form-designer/">form-designer 0.24</a>: Updated the
package for django-recaptcha 4.0.</li>
<li><a href="https://pypi.org/project/html-sanitizer/">html-sanitizer 2.3.1</a>: Fixed an
edge case sanitization bug (luckily without security implications).</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor
6.4.2</a>:
django-content-editor now again supports transitioning plugin fieldsets when
opening <em>and</em> closing thanks to CSS grid’s ability to animate the maximum
height of an element. Also, the initialization in 6.4 was badly broken.</li>
<li><a href="https://pypi.org/project/django-prose-editor/">django-prose-editor 0.2</a>: <a href="https://406.ch/writing/django-prose-editor-prose-editing-component-for-the-django-admin/">See the announcement blog post from Wednesday</a>.</li>
</ul>Weeknotes (2024 week 07)https://406.ch/writing/weeknotes-2024-week-07/2024-02-16T12:00:00Z2024-02-16T12:00:00Z<h1 id="weeknotes-2024-week-07"><a class="toclink" href="#weeknotes-2024-week-07">Weeknotes (2024 week 07)</a></h1>
<p>This is a short weeknotes entry which mainly contains a large list of releases. The reason for the large list is that I haven’t published a weeknotes entry in weeks.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/form-designer/">form-designer 0.23</a>: Only small changes, mainly updated the package for current Django and Python versions.</li>
<li><a href="https://pypi.org/project/feincms3-cookiecontrol/">feincms3-cookiecontrol 1.4.6</a>: A minor change: Swallow exceptions which happen during startup when clobbering the scripts data fails. As an aside: I find it funny that I have discovered the <code>.f3cc</code> class in some cookie banner blocklists. It feels good to be recognized even if this maybe isn’t the nicest way, but it works for me since I actually do not like cookie banners either. At least feincms3-cookiecontrol doesn’t inject anything without users’ consent, and doesn’t require a third party service to run.</li>
<li><a href="https://pypi.org/project/django_simple_redirects/">django-simple-redirects 2.2.0</a>: Minor release which adds a search field to the admin changelist. django-simple-redirects is a repackaged version of <code>django.contrib.redirects</code> without the <code>django.contrib.sites</code> dependency.</li>
<li><a href="https://pypi.org/project/speckenv/">speckenv 6.2</a>: <code>django_cache_url</code> now supports parsing redis configuration for a leader-replica redis installation with a read-write leader host and read-only replica hosts. I use the same configuration format as <a href="https://github.com/epicserve/django-cache-url">django-cache-url</a> does.</li>
<li><a href="https://pypi.org/project/django-debug-toolbar/">django-debug-toolbar 4.3</a>: I haven’t done much here, just some reviewing here and there. I enjoy the Djangonaut Space contributions a lot.</li>
<li><a href="https://pypi.org/project/django-cabinet/">django-cabinet 0.14</a>: I have removed the constraint which enforces unique names for subfolders. Enforcing the uniqueness does make sense, but it also makes bulk-updating the media library using serialized data more painful than it should be. It’s a clear case of worse is better for me. If people want to confuse themselves I’m not going to stop them (anymore, in this case) but it makes the rest of the code so much easier to write that it’s not even funny.</li>
<li><a href="https://pypi.org/project/html-sanitizer/">html-sanitizer 2.3</a>: This release contains a nice contribution which removes some whitespace which has been added by the sanitizer when merging adjacent tags of the same type, e.g. <code><strong>abc</strong><strong>def</strong></code>.</li>
<li><a href="https://pypi.org/project/django-ckeditor/">django-ckeditor 6.7.1</a>: See above.</li>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor 0.0.11</a>: Fixed a crash which happened when not providing the optional (!) configuration. Shit happens. I should really have a test suite for this package.</li>
<li><a href="https://pypi.org/project/feincms3/">feincms3 4.5.2</a>: Disables the CKEditor version check.</li>
<li><a href="https://pypi.org/project/django-content-editor/">django-content-editor 6.4</a>: The first release since December 2022! Very stable software. The editor now restores the collapsed state of inlines and the scroll position when using “Save and continue editing”. This is especially useful if editing an object with many content blocks.</li>
</ul>Weeknotes (2024 week 03)https://406.ch/writing/weeknotes-2024-week-03/2024-01-17T12:00:00Z2024-01-17T12:00:00Z<h1 id="weeknotes-2024-week-03"><a class="toclink" href="#weeknotes-2024-week-03">Weeknotes (2024 week 03)</a></h1>
<h2 id="djangonaut-space"><a class="toclink" href="#djangonaut-space">Djangonaut Space</a></h2>
<p>I wish all participants a good time and much success. I do not have anything to do with it really but I enjoy the idea a lot and maybe there will be a pull request or two to review.</p>
<h2 id="kubernetes"><a class="toclink" href="#kubernetes">Kubernetes</a></h2>
<p>After years and years of hosting all sites on VPS I have finally reached the point where the old setup is more annoying to work with than switching to a new one. I have searched long for a solution which wasn’t as limited as some PaaS and as complex as going full Kubernetes, and where I can still delegate the responsibility of actually keeping things up and running to other people. In the end I have now accepted that such a thing doesn’t exist; either you have the limitations of a ready made solution, the limitation of having to open many many support tickets or the problem of having to learn Kubernetes (or something similar) with its extremely steep learning curve.</p>
<p>After spending days with it I’m slowly getting to the point where setting up local development environments and deploying changes is fun again. I’m using the GitOps paradigm; while I’m still building and uploading Docker (podman) images from the local development environment everything else is automated and goes through a Git based process. That’s much nicer than clicking around in some interface or copy pasting obscure commands into the console.</p>
<p>The biggest problem I encountered was (perhaps unsurprisingly) managing secrets as a team. It seems to me that while <a href="https://github.com/bitnami-labs/sealed-secrets/">sealed secrets</a> work great as an individual developer they don’t really offer straightforward solutions to avoid different people overwriting and resetting each others secrets when updating them. I’m a happy user of the external secrets operator and using some cloud service to actually store those secrets.</p>
<p>I have started using <a href="https://github.com/emmett-framework/granian/">granian</a> in production. I like the idea of a Rust-based ASGI/WSGI server. Nothing mission critical yet. My idea is to build confidence in the software stack.</p>
<h2 id="compulsory-social-measures"><a class="toclink" href="#compulsory-social-measures">Compulsory social measures</a></h2>
<p>The more I learn about how Switzerland treats its citizens the more I wonder about the ways in which humans can mistreat other humans in a so called civilized and peaceful society.</p>
<p>It’s not exactly a new topic for me, but working on platforms which help remember and which help introducing people to the history certainly causes a heightened awareness for issues such as these.</p>
<p><a href="https://www.bj.admin.ch/bj/en/home/gesellschaft/fszm.html">More on this</a>.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/feincms3-sites/">feincms3-sites 0.20.2</a>: It
previously wasn’t possible to filter the list of sites to only show those
sites which do <em>not</em> have a default language. This has been fixed.</li>
<li><a href="https://pypi.org/project/django-json-schema-editor/">django-json-schema-editor 0.0.10</a>: It’s now actually possible to use the JSON editor outside inlines! That was a fun bug… not. Apart from the mentioned bug this new release mostly contains fixes to the styles. We’re slowly getting there.</li>
<li><a href="https://pypi.org/project/django-mptt/">django-mptt 0.16</a>: I didn’t do anything except for the changelog and the release. That’s alright. The release contains a few minor fixes.</li>
</ul>Weeknotes (2024 week 01)https://406.ch/writing/weeknotes-2024-week-01/2024-01-03T12:00:00Z2024-01-03T12:00:00Z<h1 id="weeknotes-2024-week-01"><a class="toclink" href="#weeknotes-2024-week-01">Weeknotes (2024 week 01)</a></h1>
<p>First weeknotes post for 2024! Happy new year!</p>
<h2 id="looking-back-on-2023"><a class="toclink" href="#looking-back-on-2023">Looking back on 2023</a></h2>
<h3 id="writing"><a class="toclink" href="#writing">Writing</a></h3>
<p>I have published almost 40 posts last year. That’s almost as many posts as I published in the time period from 2014 to 2023. <a href="https://jacobian.org/2021/mar/9/coworking-to-write-more/">Coworking to write more</a> does work.</p>
<p>I already had a quite active blog from 2005 to 2008 with a few posts after that; everything before 2014 was in german and mainly concerned with green politics and climate change. I’m still very interested in these topics but I don’t feel as if I have much to add to the conversation, even though it’s the more important issue.</p>
<h3 id="open-source"><a class="toclink" href="#open-source">Open Source</a></h3>
<p>Not much changed here. I enjoy basically everything I do in open source land, and co-maintaining the Django Debug Toolbar with Tim is a joy.</p>
<p>I still wish that some of my projects had more impact in Django land, especially those who augment the Django administration interface to be a lightweight CMS which requires very little maintenance and work in the long run. I think it’s great that one of the core components, <a href="https://pypi.org/project/django-content-editor/#history">django-content-editor</a>, hasn’t required a release in more than one year. It doesn’t have to be expanded because it just works. It would be great if there was a good way to <a href="https://406.ch/writing/managing-complexity-and-technical-debt-by-releasing-open-source-software/">distinguish</a> between software which basically doesn’t require any updates and software which is abandoned.</p>
<p>The only project which doesn’t bring me much joy is django-mptt. Most people accept that there are no guarantees, but some people are just rude in the way in which they expect others to do the work. The first reaction was to return the blow and I’m glad that I didn’t give in to the temptation to do that. It’s basically never worth it to do that in writing.</p>
<h3 id="family"><a class="toclink" href="#family">Family</a></h3>
<p>We had a good 2023 together and I’m very much looking forward to a just as good 2024.</p>
<h2 id="plans-for-2024"><a class="toclink" href="#plans-for-2024">Plans for 2024</a></h2>
<p>I have bought a ticket for the <a href="https://2024.djangocon.eu/">DjangoCon Europe 2024</a> in Spain and I’m very much looking forward to that.</p>
<p>Maybe we’ll visit a music festival again this summer. After listening to a lot of metal music in the last ten or more years I rediscovered the dark side of D’n’B. Good times.</p>
<h2 id="advent-of-code"><a class="toclink" href="#advent-of-code">Advent of Code</a></h2>
<p>I have finished the Advent of Code with some help from the Subreddit. Almost all of the puzzles were fun to think about. I didn’t have fun solving each and everyone of them, especially not the second part of a few of the later days. I feel good checking out solutions from other people in the subreddit, and maybe adding newly gained ideas to my code or even running someone else’s code 1:1 on my data after studying the algorithms used and hopefully learning something.</p>
<p>I had a good time and enjoyed shutting down the computer after that.</p>
<h2 id="releases"><a class="toclink" href="#releases">Releases</a></h2>
<ul>
<li><a href="https://pypi.org/project/FeinCMS/">FeinCMS 23.12</a>: A few minor changes to
the thumbnailing code. It’s always nice to hear from people who are still
using this project.</li>
</ul>