Django Database Performance Optimization Using Python Set Operations
Preface Recently there was a new requirement: Personnel basic information (referred to as Personnel A), 100k A certain type of personnel information (referred to as Personnel B), 1000 The requirement is to display separately in the backend (Django Admin): the list of Personnel B already entered in A, and the list of Personnel B not yet entered The team's DBA suggested using a view to solve this problem (as expected from a database person) PS: At first I thought Django's Model directly manages database tables, so using Model to map a database model might be somewhat troublesome, but after looking it up I found that's not the case~ Just
目录10 个章节
Preface
Recently there was a new requirement:
- Personnel basic information (referred to as Personnel A), 100k
- A certain type of personnel information (referred to as Personnel B), 1000
The requirement is to display separately in the backend (Django Admin): the list of Personnel B already entered in A, and the list of Personnel B not yet entered
The team's DBA suggested using a view to solve this problem (as expected from a database person)
PS: At first I thought Django's Model directly manages database tables, so using Model to map a database model might be somewhat troublesome, but after looking it up I found that's not the case~
You just need to add
managed = Falsein the Model's Meta subclass, and set thedb_tableattribute to the view name
But this project is written in Django, and I figured since we have such a handy ORM, why go to the extra trouble of implementing the functional logic in SQL?
So with a wave of my hand: no way, we'll do this in Python!
Rough Implementation
There are quite a few ways to implement this. You could add a method on the Model, such as is_in_a(), and inside it check whether that Personnel B is in Personnel A
You could also add a field in the admin configuration~
In the end I added a new method on the Model. Of course you don't have to limit yourself to this approach—Django is quite flexible.
The method looks roughly like this
def is_in_a(self) -> bool:
from apps.people.models import PersonA
queryset = PersonA.objects.filter(id_number=self.id_number)
return queryset.exists()
is_in_a.short_description = '是否已录入'
is_in_a.boolean = True
OK, no issues. Next, configure admin
@admin.register(PersonB)
class PersonBAdmin(admin.ModelAdmin):
list_display = ['name', 'id_number', 'is_in_a']
This way it can be displayed normally in the backend, and is_in_a can be used just like a regular model field
However, if you want to add a filter, that won't work—admin's default list_filter can only support database fields
To add our custom field to the filters, we can only write a Filter ourselves
First, let's look at a wrong example
class IsInAFilter(admin.SimpleListFilter):
title = '是否已录入'
parameter_name = 'is_in_a'
def lookups(self, request, model_admin):
return (
('true', '已录入'),
('false', '未录入')
)
def queryset(self, request, queryset):
raw_ids = []
if self.value() == 'true':
for item in queryset:
if item.is_in_a():
raw_ids.append(item.pk)
if self.value() == 'false':
for item in queryset:
if not item.is_in_a():
raw_ids.append(item.pk)
return queryset if self.value() is None else queryset.filter(pk__in=raw_ids)
After writing it, just put it in the admin filter configuration
list_filter = [IsInAFilter]
It works, sure, but filtering is extremely slow, because when rendering the list, every item has to hit the database once (frankly, this kind of code is shit)
PS: Unfortunately, this code was copied from a project I wrote two years ago (runs away)
Optimization Approach
I definitely couldn't stand for this
What I hate most is people writing shit-mountain code
What's more, this was my own shit, even less tolerable
Time to start optimizing the code right away!
Calm down, think it through a bit
What's slow about this is that every item in the list has to check whether id_number is in Personnel A. So why not switch to batch checking?
When I think of batch, I think of values_list, using it to generate two lists of id_number. And once we have two lists, isn't that just set operations?
That's settled, let's do it!
Sets
First, a quick review of sets
This should be high school math
A set is the grouping of several objects into one or more wholes of various forms and sizes. Generally speaking, a set is a whole of things that share a certain characteristic, or a collection of certain identified objects. The things or objects that constitute a set are called “elements” or “members”. The elements of a set can be anything: they can be people, objects, or letters or numbers, and so on.
The three main properties of sets
Unorderedness: In a set, every element has equal status; there is no order among the elements.
- An order relation can be defined on a set, and once an order relation is defined, the elements can be ordered according to it. But as far as the properties of the set itself are concerned, there is no inherent order among the elements. (See order theory)
Distinctness: In a set, any two elements are considered different, i.e., each element can appear only once.
- Sometimes you need to describe the situation where the same element appears multiple times; you can use a multiset, whose elements are allowed to appear more than once.
Determinacy: Given a set and any given element, that element either belongs to the set or does not belong to the set—one of the two must hold; ambiguous cases are not allowed.
No need to delve deep into the math concepts. Sets in programming languages are also somewhat different from mathematical sets, but they both have distinctness, meaning there are no duplicate elements in a set.
Set Operations
To achieve the performance optimization mentioned earlier, here we only need to master a few set operations
Let a and b be two different sets
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
Just look at the table for the four operations
| Operation | Code | Description |
|---|---|---|
| Difference | a - b | Elements contained in set a but not in set b |
| Union | `a | b` |
| Intersection | a & b | Elements contained in both set a and set b |
| Symmetric difference | a ^ b | Elements not contained in both a and b simultaneously |
For easier understanding, let's draw a diagram

| Operation | Result | Elements of the resulting set |
|---|---|---|
a - b | (1) | {1, 2} |
| `a | b` | (1) + (2) + (3) |
a & b | (2) | {3, 4} |
a ^ b | (1) + (3) | {1, 2, 5, 6} |
That's clear now, right~
So the problem above, simplified to set operations, is taking the intersection and the difference respectively
Final Implementation
The final implementation not only performs much better, but also has less code than before—simply perfect
def queryset(self, request, queryset):
from apps.people.models import PersonA
# 使用集合操作提高性能
set1 = set(PersonA.objects.values_list('id_number', flat=True))
set2 = set(queryset.values_list('id_number', flat=True))
id_numbers = set()
# 选择已录入的,取交集
if self.value() == 'true':
id_numbers = set1 & set2
# 选择未录入的,取差集
elif self.value() == 'false':
id_numbers = set2 - set1
return queryset if self.value() is None else queryset.filter(id_number__in=id_numbers)
Done~!
Hold On
Finally, let me recommend some good stuff I found while looking things up
Django ORM Cookbook
Chinese edition: https://django-orm-cookbook-zh-cn.readthedocs.io/zh_CN/latest/index.html
This is a book that, as the name suggests, teaches you how to use Django ORM. It has 50 examples, seems pretty good, can help fill in the gaps~
Intermediate Python
Chinese edition: https://eastlakeside.gitbook.io/interpy-zh/
Also a book, Chinese title “Python进阶”, so you should know what it's about~
References
- Set (mathematics) - Wikipedia: https://zh.m.wikipedia.org/zh/集合_(数学)
- python set operations (intersection, union, difference, symmetric difference): https://blog.csdn.net/sxingming/article/details/51922776
- Common Python set (Set) operations: https://www.jianshu.com/p/f60fabfefc09
- https://www.runoob.com/python3/python3-set.html
_EOF_
Django Database Performance Optimization Using Python Set Operations
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
比Django官方实现更好的分页组件+Bootstrap整合
前言 Django全家桶自带的分页组件只能说能满足分页这个功能,但是没那么好用就是了 Django的分页效果 django-pure-pagination分页效果 使用方法 首先安装: pip install django-pure-pagination 添加到App INSTALLED_APPS = ( ... 'pure_pagination', ) 配置一下,配置说明如图 P
2021-12-18 · Django · 约 1 分钟
配置Django-TinyMCE组件支持上传图片功能
Django自带的Admin后台,好用,TinyMCE作为富文本编辑器,也蛮好用的,这两者结合起来在做博客的时候很方便(当然博客可能更适合用Markdown来写),但是Django-TinyMCE这个组件默认没有图片上传功能的,需要我们自己实现,本文将一步步带大家实现这个图片上传功能。 读者也可以举一反三实现其他需要和Django结合的功能。 编写上传图片逻辑 在任一views.py里添加代码:
2021-12-18 · Django · 约 1 分钟
关于uwsgi服务器的管理
前言 使用Django开发项目好是好,就是部署的时候太麻烦,使用Uwsgi服务器的话,每次修改了代码,都需要重新启动服务器才可以生效。然后uwsgi服务器的重启也挺麻烦。 看了一下官网的文档,最好是把uwsgi安装到venv虚拟环境里面,这样的话在 ps aux 的时候容易区分啦。 查看uwsgi进程 ps -aux | grep uwsgi 结束原uwsgi进程 kill -9 27543 结论
2025-10-27 · Django · 约 1 分钟
实测 Django 6.0:模版片段、后台任务、CSP 安全,三大特性体验报告
呵,连WebSocket都没塞进去就敢叫大版本更新?不过模版片段和内置后台任务总算让Django像个现代框架了,至少写HTMX时不用再到处塞碎片文件。原生CSP?早该有了。至于抛弃Python 3.11——跟不上时代的版本留着也是累赘。
2026-01-20 · Django · 约 1 分钟
讨论
共 0 条加载评论中…