news 2026/10/14 4:17:22

Django ORM 单表查询全解:filter、get、Q对象与聚合实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django ORM 单表查询全解:filter、get、Q对象与聚合实战

你是不是也遇到过这种情况:模型写好了,数据也塞进去了,结果一到查询环节就卡壳。filter和get傻傻分不清,Q对象不知道怎么用,聚合查询更是看得一头雾水。网上教程东一篇西一篇,今天翻到这个,明天翻到那个,最后还是在原地点打转。

这篇文章就把 Django ORM 单表查询这件事讲透。从模型定义到环境准备,从all()到get(),从常用查询到进阶玩法,再到调试方法,一条线捋下来。每个知识点都配了实操代码和踩坑提醒,照着做就能跑通。我写的时候尽量用大白话,把抽象概念掰开揉碎,让刚接触 Django 的新手也能跟上节奏,有点基础但总在某些细节上卡壳的朋友,也能在文章里找到答案。

1. 查询前置准备:模型与数据环境

1.1 模型定义示范

Django 单表查询,说白了就是对着一个模型类进行操作。所有查询方法的演示都围绕模型展开,所以我先给出一个统一使用的模型。为了让大家有代入感,我用一个学生管理场景,包含Student模型,这也是单表查询最经典的应用场景之一。

from django.db import models class Student(models.Model): GENDER_CHOICES = [ ('M', '男'), ('F', '女'), ('U', '未知'), ] name = models.CharField('姓名', max_length=50) age = models.IntegerField('年龄') gender = models.CharField('性别', max_length=1, choices=GENDER_CHOICES) grade = models.CharField('年级', max_length=20) score = models.DecimalField('综合成绩', max_digits=5, decimal_places=2, null=True, blank=True) is_graduated = models.BooleanField('是否毕业', default=False) enroll_date = models.DateField('入学日期', auto_now_add=True) updated_at = models.DateTimeField('更新时间', auto_now=True) class Meta: db_table = 'student' ordering = ['id'] def __str__(self): return f'{self.name} ({self.grade})'

这个模型里囊括了字符串、整数、布尔、日期、Decimal 等几种常用字段类型,后面演示查询条件时基本都能覆盖到。db_table = 'student'指定了表名,实际项目中建议显式定义,不然 Django 会默认生成应用名_模型名这种格式的表名,后期维护时看着容易懵。

1.2 数据准备与 shell 环境

模型定义好了,得先准备测试数据。我个人强烈建议用 Django Shell 来跑查询语句,因为它能即时打印结果,非常适合学习阶段反复调试。连接数据库的操作就不多说了,重点是把数据准备好。

# 进入 Django shell python manage.py shell from myapp.models import Student # 批量创建测试数据 Student.objects.create(name='张三', age=18, gender='M', grade='高一', score='85.50') Student.objects.create(name='李四', age=19, gender='F', grade='高一', score='92.00') Student.objects.create(name='王五', age=17, gender='M', grade='高二', score='78.25') Student.objects.create(name='赵六', age=20, gender='F', grade='高三', score='88.00') Student.objects.create(name='孙七', age=18, gender='U', grade='高三', score=None) Student.objects.create(name='周八', age=19, gender='F', grade='高二', score='95.50') Student.objects.create(name='吴九', age=18, gender='M', grade='高三', score='60.00')

数据里故意留了一个score=None的,后面演示空值查询时就用它当典型例子。插入完成后,可以先跑一句Student.objects.count(),看看返回是不是 7,这样可以确认数据已经进去了。

2. 单表查询核心方法:all / get / filter

2.1 三种基础方法的用法与区别

Django ORM 查询的根基就三个方法:all()、get()、filter()。看似简单,实则里面的门道不少,初学者最容易在这上面栽跟头。先看基本用法:

# 查询所有记录 qs = Student.objects.all() print(qs) # 输出 QuerySet,包含所有数据 # 按主键查询单条记录 stu = Student.objects.get(id=1) print(stu.name) # 张三 # 按条件过滤,返回 QuerySet freshmen = Student.objects.filter(grade='高一')

三个方法最大的区别在于返回值类型。all()和filter()返回的是QuerySet对象,这是一个可迭代的集合;而get()返回的是单个模型实例。get()这个名字就透露了它的规则——只能查到一条记录,查不到会抛DoesNotExist,查到多条会抛MultipleObjectsReturned。

但请记住一个核心原则:get 查不到就报错,这在实际业务中非常不友好。通常我更建议用filter().first()来替代它:

stu = Student.objects.filter(id=1).first()

.first()在结果为空时返回None,不会抛异常,这样在写视图函数时就能直接用if stu:判断,省去异常处理的负担。这个习惯对开发效率提升极其明显。

2.2 QuerySet 惰性机制与常见误区

QuerySet有一个“惰性求值”特性:就是在你真正使用结果之前,Django 并不会立刻执行数据库查询。什么叫“真正使用”?就是迭代、切片、打印、布尔判断等操作。

# 这行不会执行数据库查询 qs = Student.objects.all() # 这行才会真正执行 print(list(qs)) # 或 for stu in qs 等 # 甚至这样也算触发 if qs: print('有数据')

很多新手的误区在于,以为拿到QuerySet那一刻数据库就忙活起来了。实际上,Django 会把QuerySet攒着,直到你“消费”它。这带来的核心影响是:如果你多次操作同一个QuerySet,每次操作都可能触发新的数据库查询。一个小技巧,在调试时想确认到底执行了几条 SQL,可以加一行配置:

# settings.py LOGGING = { 'version': 1, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'level': 'DEBUG', 'handlers': ['console'], }, }, }

配上之后,控制台会打印出所有 SQL 语句,非常直观。这也是我排查 N+1 问题和性能瓶颈时几乎必开的配置。

3. filter 进阶:常用条件、链式调用与模糊查询

3.1 链式调用的精髓

filter()可以叠加使用,这一点是 Django ORM 最为人称道的设计之一。多个filter()会按 AND(与)逻辑执行,作用等同于一个 filter 里写多个参数,但代码可读性会好很多:

# 写法一:多个参数 freshmen = Student.objects.filter(grade='高一', gender='M') # 写法二:链式调用,执行结果与上面完全一致 freshmen = Student.objects.filter(grade='高一').filter(gender='M') # 写法三:先查一部分,再在已有条件上追加 base_qs = Student.objects.filter(grade='高一') males = base_qs.filter(gender='M')

链式调用最大的价值在于“按需叠加,分步构建”。比如用户在页面上按不同条件筛选时,你不可能为每个组合写一遍查询代码,更合理的做法是:

qs = Student.objects.all() if grade: qs = qs.filter(grade=grade) if gender: qs = qs.filter(gender=gender) if min_score: qs = qs.filter(score__gte=min_score) # 最后统一执行 results = list(qs)

这种写法就叫“动态构建查询条件”,在实际项目里运用得非常广泛。有人可能会疑惑:多调用几次filter()会不会影响性能?我的答案是:只要没触发真正的数据库查询,构建多少个 filter 都只是内存中的组合操作,性能几乎零开销。真正花费时间的是最后一步从数据库拉取数据的过程。

3.2 模糊查询与常用字段条件

Django 的 ORM 支持用<字段名>__<查询类型>这样的双下划线语法表达各种查询条件。我整理了一份单表查询最常用的条件速查表:

查询场景写法说明
精确匹配filter(name='张三')完全相等
模糊匹配filter(name__contains='张')区分大小写的包含
忽略大小写filter(name__icontains='zhang')不区分大小写的包含
开头匹配filter(name__startswith='张')按前缀匹配
结尾匹配filter(name__endswith='三')按后缀匹配
范围区间filter(age__range=(18, 20))左右都含
大于/小于filter(age__gt=18)18 岁以上,不含 18
大于等于/小于等于filter(age__gte=18)18 岁及以上
空值判断filter(score__isnull=True)查询 score 为空
非空判断filter(score__isnull=False)查询 score 不为空
多值匹配filter(grade__in=['高一', '高三'])匹配其中一个即可

实际操作中最容易记混的是contains和icontains。前者区分大小写,后者不区分。如果数据库里存的是英文名,用contains查'Zhang'和'zhang'结果是不同的;用icontains就能避免大小写问题。对中文来说二者差异不大,但英文场景下就需要格外注意。

模糊查询在 MySQL 底层对应的是LIKE语句。contains对应LIKE '%张%',startswith对应LIKE '张%'。需要注意的是,在数据量巨大的表中,LIKE '%xxx%'这种写法命中索引的可能性很低,全表扫描的概率很高。开发阶段无所谓,但生产环境一定要压测评估。

3.3 exclude 与反向筛选

与filter对应的还有一个反向筛选方法exclude(),看名字就知道是“排除符合条件的记录”:

# 查询所有高三以外的学生 not_senior = Student.objects.exclude(grade='高三') # 也可以多个条件叠加 not_senior_male = Student.objects.exclude(grade='高三', gender='M') # 链式使用 young_not_graduated = Student.objects.filter(age__lt=19).exclude(is_graduated=True)

这里有一个容易出坑的点:exclude多个条件之间的关系是OR(或)而不是 AND。即exclude(grade='高三', gender='M')排除的是“高三”或“男生”,而不是“高三的男生”。这一点官方文档写得很清楚,但很多人初次接触时下意识当成 AND,结果查出来的数据和自己预想完全对不上。

这个特性的逻辑在于:排除多个条件时,任一条件命中的记录都不能出现在结果集中,所以条件之间的联系必须理解成“或”。刚接触时更容易理解的方式是:先过滤出要排除的集合,再从总数中取差集。虽然实现方式不同,但理解角度是相通的。

4. 排序、分页与聚合查询

4.1 排序的多种姿势

查询结果默认按模型Meta里定义的ordering排序,也就是前面模型里的['id']。如果没有定义ordering,Django 会按数据库的自然顺序返回,大多数情况下等于主键顺序,但开发时必须明确一点:不设置排序,就不保证顺序。

使用order_by()可以覆盖默认排序,支持多个字段,支持反向排序:

# 按成绩从低到高 sorted_by_score = Student.objects.order_by('score') # 按成绩从高到低 sorted_desc = Student.objects.order_by('-score') # 多字段混合排序:先按年级升序,同年级内按成绩降序 mixed = Student.objects.order_by('grade', '-score') # 条件排序和排除可以链式组合 filtered_sorted = Student.objects.filter(score__isnull=False).order_by('-score')

这里有一个经验之谈:order_by('字段名')会把空值排在最前面。NULL 值在数据库排序中默认排在最前,如果希望空值排在最后,在不同数据库里有不同写法。PostgreSQL 支持NULLS LAST,MySQL 不直接支持,这种细节在单表场景不一定用得上,但遇到了要知道有这么回事。

另外提醒一句:排序字段尽量带上索引。如果一张表几十万行,每次查询都在一个没有索引的字段上排序,总有一天会慢到怀疑人生。Django 里给字段加索引很简单,在模型定义里加一个db_index=True就行。

4.2 分页取数与切片操作

分页是 Web 开发中最常见的需求之一。获取前 N 条数据,只需要用 Python 的切片语法:

# 获取前 3 条 top3 = Student.objects.order_by('-score')[:3] # 跳过前 2 条,取接下来的 3 条 next3 = Student.objects.order_by('-score')[2:5] # 只取一条 latest = Student.objects.order_by('-id')[:1].first() # 获取倒数若干条,需要先反向排序再切片 last2 = Student.objects.order_by('-id')[:2]

切片操作有两个隐藏要点:

第一,切片相当于 SQL 层面的LIMIT和OFFSET,不会先加载全部数据再在内存里切。因此性能可以放心,这种方式对于大表也能保持高效。

第二,对 QuerySet 做切片后返回的仍然是 QuerySet,依旧是惰性的。但如果你做的是qs[2]这种“只拿第 3 条”的操作,Django 会立即执行 SQL,并且在 SQL 里体现为LIMIT 1 OFFSET 2。这个机制在开发时需要留意,尤其在循环里反复用qs[i]获取数据,会带来严重的性能问题(每次取一条都要发一条 SQL)。

4.3 聚合查询:count / sum / avg

单表查询的进阶玩法就是聚合了。Django 提供了一套封装良好的聚合操作方法,覆盖了统计场景的大多数需求:

from django.db.models import Count, Sum, Avg, Max, Min # 查询总数 total = Student.objects.count() # 等价写法 total = Student.objects.all().aggregate(Count('id')) # 查询成绩总和 total_score = Student.objects.filter(score__isnull=False).aggregate(Sum('score')) # 查询平均分 avg_score = Student.objects.filter(score__isnull=False).aggregate(Avg('score')) # 同时查多个聚合值 stats = Student.objects.aggregate( total=Count('id'), avg_age=Avg('age'), max_score=Max('score'), min_score=Min('score'), )

aggregate()和annotate()是容易混淆的一对兄弟。aggregate()返回的是一个字典,对整个结果集计算汇总值;annotate()则是在每个分组上计算聚合值,返回的仍然是 QuerySet。这个区别在单表查询中体现为“是否按某个字段分组”:

from django.db.models import Count # 按年级统计人数,返回 QuerySet,每行是一个年级 grade_counts = Student.objects.values('grade').annotate( total=Count('id') ) # 具体输出长这样 # <QuerySet [{'grade': '高一', 'total': 2}, {'grade': '高二', 'total': 2}, {'grade': '高三', 'total': 3}]>

values('grade')的功能是“按 grade 分组”,annotate再给每组加上统计字段。这是对年级进行人数统计最高效的写法,比在 Python 里反复循环拼接要专业得多,性能也甩出好几条街。实际业务中“分组统计”是高频需求,比如统计各商品销量、各部门人数、各月份订单量,思路完全一样。

5. 复杂条件组合:Q 对象与 F 表达式

5.1 Q 对象的用法与 OR 查询

前面演示的所有查询都是 AND 关系。如果业务要求“成绩大于 90 或年级为高三”,怎么办?Django 提供了Q对象解决这个问题:

from django.db.models import Q # 查询成绩大于90 或 年级为高三的学生 result = Student.objects.filter(Q(score__gt=90) | Q(grade='高三')) # 查询既不是高一也不是高二的学生 result = Student.objects.exclude(Q(grade='高一') | Q(grade='高二')) # Q 对象可以混合普通条件 result = Student.objects.filter( Q(grade='高三') | Q(grade='高二'), age__gte=18, # 这个条件与上面的 Q 条件是 AND 关系 )

上表中最后一种写法是重点中的重点:普通关键字参数和Q对象同时出现时,普通参数作为 AND 条件与Q结合。“与”用&,“或”用|,“非”用~。这就是一个完整的布尔表达式系统,复杂筛选逻辑的根基就在这。

Q对象在动态查询条件场景中同样价值巨大。比如搜索页面,用户输入的关键词可能匹配姓名,也可能匹配年级,这时用一个Q对象就能把两个条件的“或”关系表达出来,不用写一堆if-else分支去拼接字符串,既优雅又不容易出错。

5.2 F 表达式:字段间比较

F表达式解决的是“两个字段之间比较”这类问题。举个例子:查询“男生的数量大于女生”或“更新所有人成绩加五分”,这种场景用普通 Python 变量是做不到的,因为需要在数据库层面完成字段间的比较和运算。

from django.db.models import F # 场景:查询入学日期年份大于 2020 的记录 # 先直观感受 F 表达式的作用域 Student.objects.create( name='测试', age=18, gender='M', grade='高一', score=F('age') + 10 # 注意:这里 F 不能这么用,仅作错误示例 )

上面的例子是错的,F不是用来创建数据时做运算的。正确的用法是在查询和更新场景中:

from django.db.models import F # 把所有学生的综合成绩加 5 分 Student.objects.update(score=F('score') + 5) # 查询入学日期晚于今年1月1日的学生(能理解思路即可) from datetime import date target_date = date(date.today().year, 1, 1) result = Student.objects.filter(enroll_date__gte=target_date) # 查询“年龄大于综合成绩”的学生(纯示意,分数和年龄量纲不同) result = Student.objects.filter(age__gt=F('score'))

第一个场景是F表达式最实际的用途:在数据库层面直接对某个字段做更新,而不是先把数据取到 Python 内存中修改再写回去。后者要循环处理,遇到并发还会产生数据竞争;前者发送的 SQL 是UPDATE student SET score = score + 5,原子性强且高效。

F表达式还有一个优势是避开“取数据-改数据-写数据”三步带来的时间窗口问题。在并发环境下,用 Python 读出来再写回去,极易出现“丢失更新”。用F直接在数据库内部完成运算,可以规避这类问题。

6. 查询实战:数据展示与防坑指南

6.1 把查询结果传到模板

单表查询最终的目标是把数据展示到页面上。一个最常见的流程是:视图里查数据,传到模板,模板里遍历。以“展示高一学生列表”为例:

# views.py from django.shortcuts import render from .models import Student def student_list(request): students = Student.objects.filter(grade='高一').order_by('-score') context = { 'students': students, 'total': students.count(), } return render(request, 'student/list.html', context)

模板里这样写:

<table> <thead> <tr> <th>姓名</th> <th>年龄</th> <th>成绩</th> </tr> </thead> <tbody> {% for stu in students %} <tr> <td>{{ stu.name }}</td> <td>{{ stu.age }}</td> <td>{{ stu.score|default:"暂无成绩" }}</td> </tr> {% empty %} <tr><td colspan="3">暂无数据</td></tr> {% endfor %} </tbody> </table>

这里有两个小细节值得新手关注。

第一是{% empty %}标签。如果查询结果为空,模板不会报错,而是会执行{% empty %}中的内容。用这个标签可以让页面在没有数据时显示友好提示,而不是一张空白表格。第二是|default:"暂无成绩"过滤器。score字段允许为None,直接在页面上一显示会变成空白,加上过滤后就能对空值做出友好展示。

6.2 表字段遍历与动态展示

模板语法里有一个实用的技巧:如果需要在模板中根据某个字段名动态取值,可以用{% with %}配合变量拼接?其实 Django 模板不支持变量名拼接,但这种需求可以通过把字段名作为字符串传入values_list或getattr来解决。模板里最常用的是直接通过属性访问:

# 视图里把想展示的字段列表传给模板 field_list = ['name', 'age', 'grade', 'score']

模板中遍历字段名,再通过obj|getattr方式取值,需要自定义过滤器。不过对大多数场景来说,直接在模板中写死字段名更直白,也更不容易出错。单表查询的模板展示重点在于:查询做好排序和过滤,展示层保持简单。不要在模板里写复杂逻辑,这是 Django 的哲学。

6.3 常见坑位排查速查表

单表查询的坑说来说去就那么几个,但每一个都可能浪费你半小时甚至更久。我把最常见的陷阱和解决方法做成一张表格,方便对照排查:

现象根本原因解决方案
查询结果全表返回,过滤条件无效把all()和filter()分开用了,比如先查 all 之后再内存过滤在查询层面用filter(),不要先取全量再 Python 过滤
get()频繁抛异常数据本身有多条或零条换成.filter().first()
列表页展示字段为空字段本身是None,模板没做空值处理模板里加default过滤器
使用contains查英文数据无结果大小写不匹配换成icontains
排序结果不达预期多个字段排序时顺序写反按 SQL 排序逻辑检查order_by字段顺序
更新时把所有记录都改了用了update()但没有加条件先.filter()限制范围再update
查询耗时长,数据量大查询条件字段没加索引在模型字段上设置db_index=True
exclude结果与预期不符多个条件之间是 OR 逻辑用~Q(...)替代

6.4 调试利器:QuerySet 的 SQL 查看

写查询的时候,心里时刻要有一句话:“这个查询最终生成的 SQL 长什么样?”如果不清楚,就说明你对 ORM 的理解还停留在背 API 的阶段。有一个非常实用的调试方法:

# 在 shell 中打印 QuerySet 对应的 SQL 语句 qs = Student.objects.filter(grade='高三').order_by('-score') print(qs.query) # 输出类似:SELECT * FROM student WHERE grade = 高三 ORDER BY score DESC

qs.query属性专门用于输出 QuerySet 对应的 SQL 语句,可以帮助你直观理解 Django 在数据库层面到底做了什么。另一个角度是,在理解了底层 SQL 之后,回到 Django 查询 API 时会非常有底气。因为你知道filter(score__gte=90)最终生成的是WHERE score >= 90,遇到数据库层面的优化问题也能独立找到思路。

如果要查看带参数的完整 SQL,需要开启日志。用上面提到过的django.db.backends的日志配置,控制台会打印执行的全部 SQL 和对应参数。这在调试问题时几乎是终极武器。

7. 补充场景与避坑总结

7.1 空值处理的进阶推荐

在查询结果中遇到空值(None)时,有人喜欢在 Python 端补默认值,有人喜欢在数据库端处理。如果数据量不大,Python 端处理完全可行。但要养成一个习惯:查询阶段就把空值过滤掉或处理掉,不要等展示时再临时处理。

# 查询时忽略没有成绩的 Student.objects.filter(score__isnull=False) # 查询时把空值替换为 0 分(数据库端处理) from django.db.models import Value from django.db.models.functions import Coalesce qs = Student.objects.annotate( display_score=Coalesce('score', Value(0)) )

Coalesce函数能实现在 SQL 层面把NULL转成默认值。第一次用的时候你可能会觉得一个空值而已,搞这么复杂干什么。但真正的好处在于:这个转换在数据库查询阶段就完成了,不会对应用层性能和代码复杂度产生额外负担,处理十万条数据时差距就很明显。

7.2 工具函数封装:复用你的查询

开发越深入,越会发现查询逻辑的复用价值。与其在视图里反复写同一套查询,不如封装成独立的工具函数或模型的静态方法:

class Student(models.Model): # ...字段定义... @staticmethod def get_avg_score_by_grade(grade): return Student.objects.filter(grade=grade).aggregate(Avg('score'))

调用时只需要Student.get_avg_score_by_grade('高三'),逻辑集中且便于测试。这个习惯也符合 Django 项目常见的“业务逻辑下沉到模型层”的做法,视图保持轻量,维护性大大提升。如果一个查询逻辑要被多处复用,封装它是唯一的正解。

7.3 个人操作心得

单表查询是整个 Django ORM 的地基,也是后续学习跨表查询、性能调优的前提。它本身入门门槛不高,函数就那几个,参数就是双下划线语法,但真正的分水岭在于你如何组织它们去解决实际业务问题。

按我自己的开发习惯,总结了几条实操铁律,可以给大家当个参考:

第一,规则上只做必要查询。减少全表all()的使用频率,哪怕是控制台调试,也尽量带上过滤条件。第二,所有多条件筛选写成链式调用,不要追求“一行写完”,可读性比炫技重要得多。第三,涉及聚合统计时提前算好数据结构,直接把查询结果按业务需求聚合好,不要在 Python 里做二次内存统计。第四,写完查询后打印一次qs.query,确认 SQL 与业务意图一致,这是对自己代码负责的表现。

记住这些习惯,写单表查询就能少踩很多坑。学习 ORM 就是一个不断练习、不断看生成的 SQL、不断修正自己认知的过程。把这些基本功打扎实了,再去碰 select_related、prefetch_related 这些跨表优化技巧,就会觉得水到渠成、顺理成章。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 4:15:47

Linux系统管理命令详解:从top到journalctl的运维实战

运维这行干久了&#xff0c;你会发现一个规律——真正拉开差距的不是你会不会部署某个服务、能不能写出漂亮的脚本&#xff0c;而是当你面对一台状况不明的服务器时&#xff0c;能不能用最基础的命令快速定位问题。我刚带团队那会儿&#xff0c;很多新人问我“系统管理命令”到…

作者头像 李华
网站建设 2026/10/14 4:15:06

批量PPT转PDF:VBA与PowerShell自动化脚本实战

估计不少朋友都遇到过这种场景&#xff1a;领导发来一个文件夹&#xff0c;里面有几十份PPT&#xff0c;要求“今天下班前统一转成PDF发出去”。或者你自己开完客户汇报会&#xff0c;手里攒了一堆演示文稿&#xff0c;需要归档成统一格式。手动一个个打开、另存为PDF&#xff…

作者头像 李华
网站建设 2026/10/14 4:15:05

System V共享内存实战:从IPC原理到Linux进程间同步

做 Linux 下开发的人&#xff0c;早晚都会碰到同一个问题&#xff1a;两个进程要交换数据&#xff0c;用管道要拷贝&#xff0c;用消息队列也要拷贝&#xff0c;数据量一上去&#xff0c;CPU 占用和拷贝延迟就很扎眼。System V 共享内存是我个人的首选方案之一&#xff0c;理由…

作者头像 李华
网站建设 2026/10/14 4:14:58

软件界面设计公司设计的新趋势:用好有效摩擦,拒绝无效麻烦

导语 过去二十年&#xff0c;互联网设计的共识是极致去摩擦&#xff1a;缩短注册步骤、精简操作链路、抹平交互门槛&#xff0c;高效顺滑成为体验标配。但随着全行业体验同质化、用户划走即遗忘&#xff0c;Burberry 慢镜头广告、Apple Liquid Glass 拟物玻璃界面、CCD 胶片回…

作者头像 李华
网站建设 2026/10/14 4:14:50

C++ const 完全指南:语法、类型系统与工程实践中的常量正确性

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/14 4:14:38

Sam3图像分割模型Windows本地部署与Demo调试指南

终于把Sam3在Windows本机跑通了&#xff0c;连带一个能直接玩的demo也调了出来。这里的Sam3&#xff0c;指的图像分割模型系列在迭代到第三代后社区里比较常用的叫法&#xff0c;它的核心能力很直白&#xff1a;给一张图&#xff0c;自动把图片里的物体边界抠出来&#xff0c;支…

作者头像 李华