on software
Posts from blog by tag django:

Under the Hood of Spense.app: The Code.

This article is a translation and adaptation of my article in Russian.

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 more

This Week in Changelogs: Django and faker

Django 4.1.6, 4.1.7

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!

26b7a25 There was a bug in generated SQL, caused by that .desc() in the model's Meta.constraints:

constraints = [
        Lower("name").desc(), name="unique_lower_name"

which resulted in <...> WHERE LOWER("myapp_foo"."name") DESC <...> when checking the uniqueness. Apparently, Django can check the constraints itself, not delegating it to the underlying database.

Although the fix is trivial, the case is not, and it wasn't covered in the initial implementation.

By the way, I like how they use typographic double quotes:

msg = "Constraint “name_lower_uniq_desc” is violated."

a637d0b f3b6a4f Those black updates are annoying, mainly because they make git blame misleading. However, there's a solution I didn't know about:

  • git blame --ignore-revs-file <file> - ignore commits listed in the file.
  • .git-blame-ignore-revs file - make GitHub ignore them as well.

590a92e The bug was caused by the commit which we've already seen. Now you can safely raise ValidationError without the code.

628b33a One more DoS fix, now it's about number of opened files when you put too many of them in one multipart payload. The fix introduces TooManyFilesSent exception, which results in HTTP 400 (DATA_UPLOAD_MAX_NUMBER_FILES = 100 by default).

I like this fragment:

    return self._parse()
except Exception:
    if hasattr(self, "_files"):
        for _, files in self._files.lists():
            for fileobj in files:

Beware of freeing your resources, garbage collector can't help you all the time!

faker 16.6.1..17.0.0

Their CHANGELOG is quite descriptive, so I'll just highlight something that I liked.

  • faker can generate valid image URLs using specific websites (TIL), and one of them, PlaceIMG, is shutting down, and they removed it from the list. The announcement is included in all the generated images:

In addition, it turned out that GitHub can put those linter errors from the actions right in the code. I don't know yet how to add this, but I definitely want it!