← Julia Evans (jvns.ca)

System.Xml.XmlElement

系统.Xml.XmlElement
2026-07-21T00:00:00+00:00  ·  Julia Evans (jvns.ca)  ·  原文

Hello!

你好!

I’m on a funny journey right now where I’m trying to learn how to make websites in a sort of 2010 style, where I have an SQL database and render some HTML on the backend.

我现在正处于一个有趣的旅程中,我正在尝试学习如何以 2010 年风格制作网站,我有一个 SQL 数据库并在后端呈现一些 HTML。

It’s kind of an interesting journey because it doesn’t necessarily feel “easy” to me to make websites in this way: I never learned how to do it in the 2000s or 2010s, and there’s a lot I need to learn.

这是一次有趣的旅程,因为对我来说,以这种方式制作网站并不一定感觉“容易”:我在 2000 年代或 2010 年代从未学会过如何做,而且我需要学习很多东西。

So here are some Django features that make building this kind of site feel more achievable than when I was trying and failing to use Go’s standard library or Flask.

因此,这里有一些 Django 功能,使构建此类网站比我尝试使用 Go 的标准库或 Flask 但失败时感觉更容易实现。

And I’ll talk about a couple of issues with Django I’ve run into.

我将讨论我遇到的 Django 的几个问题。

I really liked this frontend-heavy approach for these super simple applications but when I started thinking about making something with a lot of different pages (instead of literally just one page), I didn’t feel so excited about the options I saw that involved a lot of frontend code.

对于这些超级简单的应用程序,我真的很喜欢这种前端密集型方法,但是当我开始考虑用很多不同的页面(而不是实际上只有一页)制作一些东西时,我对看到的涉及大量前端代码的选项并没有感到那么兴奋。

So I figured I’d try the backend.

所以我想我应该尝试一下后端。

Writing a backend-focused site that uses as little JS as possible feels the same to me in a way as writing a single-page JS website that does as little on the backend as possible, even though they might seem like opposites.

对我来说,编写一个使用尽可能少的 JS 的以后端为中心的网站,就像编写一个在后端上尽可能少做事的单页 JS 网站一样,尽管它们可能看起来相反。

In both cases I’m just trying to keep as much of the logic as possible in one place.

在这两种情况下,我只是试图将尽可能多的逻辑保留在一个地方。

Now for some thoughts about Django!

现在谈谈关于 Django 的一些想法!

I’m enjoying query builders I learned that I can define a “query set” class in Django with a bunch of methods with different WHERE statements I might want to use while constructing a query:

我很喜欢查询构建器,我了解到我可以在 Django 中定义一个“查询集”类,其中包含一堆方法,这些方法具有我在构建查询时可能想要使用的不同 WHERE 语句:

Here’s how I use it in my view code once I’ve defined what all the methods mean:

定义了所有方法的含义后,我将在视图代码中使用它,如下所示:

Events.objects.approved() .for_tab(tab) .with_festivals(tab_params.festival_slugs) .is_free(tab_params.free) .is_outdoors(tab_params.outdoors) and here’s how I define the methods:

Events.objects.approved() .for_tab(tab) .with_festivals(tab_params.festival_slugs) .is_free(tab_params.free) .is_outdoors(tab_params.outdoors) 以下是我定义方法的方式:

class EventQuerySet(SearchableQuerySetMixin, models.QuerySet): def approved(self): return self.filter(approved_at__isnull=False) def future(self): today = timezone.localdate() return self.filter(end__gt=self._midnight(today)) def with_tags(self, tags): if tags: return self.filter(tags__name__in=tags).distinct() return self The syntax for defining the filters isn’t my favourite, but I spend most of my time just using the methods, and it feels super readable and nice to use, and it makes me want to look into other query builder libraries in the future.

class EventQuerySet(SearchableQuerySetMixin, models.QuerySet): defroved(self): return self.filter(approved_at__isnull=False) def future(self): Today = timezone.localdate() return self.filter(end__gt=self._midnight(today)) def with_tags(self, Tags): if Tags: return self.filter(tags__name__in=tags).distinct() return self 定义过滤器的语法不是我最喜欢的,但我大部分时间都花在使用这些方法上,它感觉超级可读且很好用,这让我想在未来研究其他查询构建器库。

In the past I thought “I know SQL, who needs a query builder?”, but this kind of structure does make it really nice to read.

过去我想“我懂 SQL,谁需要查询生成器?”,但这种结构确实使它读起来非常好。

I found an example of someone who wrote their own small query builder in Python that I want to read later to think about whether I would enjoy using a more minimal version of this.

我发现了一个例子,有人用 Python 编写了自己的小型查询生成器,我想稍后阅读该示例,以思考我是否会喜欢使用它的更简单的版本。

There are a bunch of little quality of life filters available in Django templates that are super useful for generating HTML.

Django 模板中有许多小质量过滤器,对于生成 HTML 非常有用。

The ones I’ve used so far are:

到目前为止我用过的有:

These are all small things individually but I feel like it makes a big difference somehow to just have them available.

这些都是单独的小事情,但我觉得只要拥有它们就会产生很大的不同。

I think my favourite template filter is querystring : in this site sometimes we use filters like ?date=2026-06-01 to decide what’s displayed.

我认为我最喜欢的模板过滤器是 querystring :在这个网站中,有时我们使用像 ?date=2026-06-01 这样的过滤器来决定显示的内容。

querystring that will make a link to the same query string with one change, like this to link to the previous date:

querystring 将通过一次更改来链接到同一查询字符串,如下所示链接到前一个日期:

automatic database migrations are still great I still really love Django’s automatic database system.

自动数据库迁移仍然很棒我仍然非常喜欢 Django 的自动数据库系统。

It’s amazing to be able to just edit a model to add a new field or whatever, and then Django automatically generates the migration.

令人惊奇的是,只需编辑模型以添加新字段或其他内容,然后 Django 就会自动生成迁移。

So far we have done 19 database migrations and I think there will probably be more!

到目前为止,我们已经完成了 19 次数据库迁移,我认为可能还会有更多!

It makes a huge difference for me to be able to just easily change the database as my understanding of the problem changes.

当我对问题的理解发生变化时,能够轻松地更改数据库,这对我来说是一个巨大的改变。

Django’s documentation sometimes offers the option of using class-based views and inheritance to organize the code in your views.

Django 的文档有时提供使用基于类的视图和继承来组织视图中的代码的选项。

For example I have four views that share a lot of code, and I could use inheritance to manage that by defining some kind of parent class and then having my other views inherit from it.

例如,我有四个共享大量代码的视图,我可以使用继承来管理它,方法是定义某种父类,然后让其他视图继承它。

I tried it out and I did not enjoy the experience of using inheritance to share code between views.

我尝试了一下,但我不喜欢使用继承在视图之间共享代码的体验。

I switched to using functions instead, sort of how this post advocates, and that was a lot more straightforward.

我转而使用函数,就像这篇文章所倡导的那样,而且更加简单。

I’ve never had a good experience using inheritance in Python and I don’t think I’ll try to use it again.

我从来没有在 Python 中使用继承的良好经验,并且我认为我不会再次尝试使用它。

But I don’t mind using inheritance to use the interfaces Django itself provides: for example if I want to define a query set I need to write something like class EventQuerySet(SearchableQuerySetMixin, models.QuerySet) .

但我不介意使用继承来使用 Django 本身提供的接口:例如,如果我想定义一个查询集,我需要编写类似 class EventQuerySet(SearchableQuerySetMixin, models.QuerySet) 的内容。

I don’t think too hard about it and it seems to work.

我并没有想太多,而且似乎很有效。

(as a meta comment: I’ve been working on talking about my programming opinions by just saying “THING does not feel good to me, I prefer OTHER THING instead”.

(作为元评论:我一直在努力谈论我的编程观点,只是说“这件事对我来说感觉不好,我更喜欢其他事情”。

That post I linked to says that function-based views are the “right way”.

我链接的那篇文章说基于功能的视图是“正确的方法”。

I’m not very invested in whether it’s “right”, but it’s validating to know that other people feel similarly to me about inheritance)

我不太关心这是否“正确”,但知道其他人对继承的看法与我相似,这很验证)

At some point the LLM scrapers discovered our site, and started sending us maybe 10 requests per second.

在某个时刻,LLM 抓取工具发现了我们的网站,并开始每秒向我们发送大约 10 个请求。

I blocked them which is working for now, but it made me think about what the site’s capacity is.

我屏蔽了它们,目前还有效,但这让我思考该网站的容量有多大。

I’m used to writing Go backends where the performance situation is pretty straightforward (usually everything is just fast enough), and a Django site is very different.

我习惯于编写 Go 后端,其中性能情况非常简单(通常一切都足够快),而 Django 站点则非常不同。

Some light load testing (with ( ab -n 1000 -c 1 ) shows that right now we can serve about 2-3 requests per second (on a ~$10/month VM).

一些轻负载测试(使用( ab -n 1000 -c 1 )表明,现在我们每秒可以处理大约 2-3 个请求(在大约 10 美元/月的虚拟机上)。

It’s tempting for me to go down a rabbit hole where I do a bunch of profiling to figure out what’s slow and try to make it faster (there’s py-spy for that, and py-spy is great and super easy to use, and profiling is fun!) But I really don’t understand what I should expect in terms of performance from a Django site and how I should be thinking about at a higher level.

对我来说,深入一个兔子洞进行大量分析来找出速度慢的地方并尝试使其更快(有 py-spy,py-spy 非常棒并且非常容易使用,而且分析很有趣!),但我真的不明白在 Django 站点的性能方面我应该期望什么,以及我应该如何在更高的层面上思考。

Some things I haven’t figured out yet: If I have a site that’s going to be getting occasional bursts of traffic, do I want to be able to scale up?

有些事情我还没有弄清楚:如果我有一个网站偶尔会出现流量激增,我是否希望能够扩大规模?

Do I want to design the site so that more things can be cached?

我想设计网站以便可以缓存更多内容吗?

(and do I really have to?

(我真的必须这么做吗?

caches are so annoying to get right!) The django performance docs say that Jinja is faster for templating, do I want to think about switching templating systems?

缓存太烦人了!)django 性能文档说 Jinja 的模板化速度更快,我是否想考虑切换模板系统?

Those docs also say “{% block %} is faster than using {% include %}”, I wonder if it’s a big difference and if so why template caching might be important I think one thing I’m learning about Django is that because it’s a Framework (tm), it’s easy to accidentally misconfigure it.

这些文档还说“{% block %} 比使用 {% include %} 更快”,我想知道这是否有很大的区别,如果是的话为什么模板缓存可能很重要我认为我学到的关于 Django 的一件事是,因为它是一个框架 (tm),所以很容易意外地错误配置它。

For example, when I was thinking about why my site was slow just now, I read the django performance docs and I noticed a comment saying:

例如,当我思考为什么我的网站现在很慢时,我阅读了 django 性能文档,并注意到一条评论说:

Enabling the cached template loader often improves performance drastically, as it avoids compiling each template every time it needs to be rendered.

启用缓存模板加载器通常会极大地提高性能,因为它避免了每次需要渲染时都编译每个模板。

When I’d done CPU profiling I’d noticed that it was spending a lot of time rendering templates!

当我完成 CPU 分析后,我注意到它花费了大量时间来渲染模板!

Maybe this could help me!

也许这可以帮助我!

Clicking through the link, I saw that the cached template loader was supposed to be on by default, but I’d turned it off by accident while trying to do something else.

单击链接,我看到缓存的模板加载器应该默认打开,但我在尝试执行其他操作时意外将其关闭。

I think this “I turned off the cached template loader by default” things is an example of how I still find the django settings file to be pretty confusing and difficult.

我认为“我默认关闭了缓存的模板加载器”就是一个例子,说明我仍然发现 django 设置文件非常混乱和困难。

I guess I should just be careful when I go in there.

我想我进去的时候应该小心一点。

After turning on template caching, it seems like the site can now pretty easily handle 12 requests per second or so without using all of the CPU.

打开模板缓存后,站点现在似乎可以轻松地每秒处理 12 个请求左右,而无需使用所有 CPU。

I have not carefully benchmarked the before and after but it seems like it’s made a pretty big difference.

我没有仔细比较之前和之后的基准,但似乎它产生了相当大的差异。

One thing that’s been surprising to me about Django performance is that I’ve always heard the advice “if you have a performance problem, check your database queries!

关于 Django 性能,令我惊讶的一件事是我总是听到这样的建议:“如果你有性能问题,请检查你的数据库查询!

Maybe add an index!”.

也许添加一个索引!”。

But I’ve been running into a variety of performance issues (like this template caching thing) that are not because of slow queries, so instead it’s been more useful for me so far to start by running a CPU profile.

但我遇到了各种性能问题(比如模板缓存问题),这些问题并不是因为查询速度慢造成的,因此到目前为止,从运行 CPU 配置文件开始对我来说更有用。

And since I’m using SQLite, any slow database query problem will show up on the CPU profile anyway.

由于我使用的是 SQLite,任何缓慢的数据库查询问题都会显示在 CPU 配置文件上。

Anyway I don’t want to get too far into site performance.

无论如何,我不想过多关注网站性能。

Like I said it’s easy for me to get interested in profiling, but actually I know a lot about profiling and it’s not the most important thing for me to learn about.

就像我说的,我很容易对分析产生兴趣,但实际上我对分析了解很多,这对我来说并不是最重要的。

I might say more about what I’m enjoying (or having a hard time with!) about Django later.

稍后我可能会更多地谈论我对 Django 的喜欢(或感到困难!)。

Trying to write some shorter blog posts recently.

最近尝试写一些较短的博客文章。

中文为机器翻译,仅供参考。