The Cartesian Product Trap in Django ORM
I hit a performance wall at work recently after adding a single extra Count() on a Django queryset that looked harmless. Luckily, the problematic code didn't make it into the production environment, but I had to think hard to figure out what went wrong and find a solution.
Why Django's override_settings Sometimes Fails (and How reload + patch Saved Me)
Sometimes @override_settings just doesn’t cut it.
I ran into a nasty issue while testing a Django module that relies on global state initialized during import. The usual test approach didn’t work. Here’s what happened and how I solved it.
Read moreUnder the Hood of Spense.app: The Code.
While Spense v0.2 is under development, I want to talk about the internal organization of the application from a technical perspective. This article is mainly for web developers, and it's written in the corresponding language, so if you're reading and don't understand anything, that's okay, you can just skip it.
In a Nutshell
Backend on Django (Python), frontend on Django templates and Bootstrap, with a pinch of JavaScript and some htmx (not anymore).
Why So Boring?
Sounds not very hype, right. But remember that Spense in its current state is not a full-fledged product. It's more of a prototype, in which I often need to change things and test ideas. If the ideas work, I'll throw this code away and write another; if they don't, I'll just keep it for memory.
So, I chose Django not because I love it (actually, I hate it), but because I've gotten used to it over the last year, and it allows me to prototype the application easily and quickly.
Read moreThis Week in Changelogs: Django and faker
Django 4.1.6, 4.1.7
- 4.1.6: release notes, blog post
- 4.1.7: release notes, blog post
9d7bd5a
An interesting bug of parsing the Accept-Language header. The format of the header value is complex, so there's a bunch of regular expressions and @functools.lru_cache(maxsize=1000) for caching the result. However, you can pass a huge header multiple times, causing DoS, so they added two if statements:
- one that checks if the length is less than
ACCEPT_LANGUAGE_HEADER_MAX_LENGTH - second - for checking the comma-separated strings. So they decided not to just raise an exception or truncate the string by
[:ACCEPT_LANGUAGE_HEADER_MAX_LENGTH], but truncate the value in a safe way, so it can be parsed in a meaningful result. Good job!


