django admin.ModelAdmin list_display 自定义的的字段,字段内容是 字符串的数字(比如说手机号码、身份证号码等等),排序的时候把出生年份取出来,然后按大小排序
annotate
转换字段类型在 ModelAdmin
中重写 get_queryset
方法,将字符串字段转换为整型,并绑定到自定义字段的排序逻辑:
from django.contrib import admin
from django.db.models import IntegerField
from django.db.models.functions import Substr, Cast
class UserAdmin(admin.ModelAdmin):
list_display = ('phone_tail',)
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.annotate(
phone_tail_int=Cast(
Substr('phone', -4, 4), # 显示后 4 位
output_field=IntegerField()
)
)
return qs
def phone_tail(self, obj):
return obj.phone[-4:] # 显示后四位
phone_tail.short_description = "手机尾号"
phone_tail.admin_order_field = 'phone_tail_int' # 绑定到转换后的整型字段
关键说明:
Substr
函数:
Substr('phone', -4, 4)
:从 phone
字段的倒数第4位开始截取4位(适用于类似 "13812345678"
的11位手机号)。Substr('phone', 7, 4)
从第7位开始截取4位)。Cast
函数:
"5678"
)转换为 IntegerField
,以便按数值大小排序。数据库兼容性:
Substr
和 Cast
。RIGHT(phone, 4)
),可通过 RawSQL
实现:
from django.db.models.expressions import RawSQL
qs = qs.annotate(
phone_tail_int=Cast(
RawSQL("SUBSTR(phone, -4)", []),
output_field=IntegerField()
)
)
Substr('id_card', 7, 8) # 截取第7位开始的8位
"ABC1234"
),需先清理数据或使用正则表达式提取数字部分(依赖数据库函数,如 REGEXP_REPLACE
)。