这与 this question 非常相似,但不幸的是,我仍然无法让它工作。
我有一个模型,它的属性结合了几个字段:
class Specimen(models.Model):
lab_number = ...
patient_name = ...
specimen_type = ...
@property
def specimen_name(self):
return f"{self.lab_number}_{self.patient_name}_{self.specimen_type}"
在 Django Admin 中,当有人进行搜索时,我可以使用 search_fields
模型管理中的属性来指定实际字段,但不是 specimen_name
自定义字段:
def specimen_name(inst):
return inst.specimen_name
specimen_name.short_description = "Specimen Name"
class SpecimenModelAdmin(admin.ModelAdmin):
list_display = ('specimen_name', 'patient_name', 'lab_number', 'specimen_type')
search_fields = ('patient_name', 'lab_number', 'specimen_type')
使用上面的代码进行搜索时,它将搜索各个字段,但是如果我尝试在 Django Admin 中搜索完整的样本名称,它将找不到它,因为没有一个字段包含准确的完整样本名称。我在上面链接的 SO 问题为我指明了正确的方向 - 使用
get_search_results
.我的代码现在看起来像这样:class SpecimenModelAdmin(admin.ModelAdmin):
...
search_fields = ('patient_name', 'lab_number', 'specimen_type')
def get_search_results(self, request, queryset, search_term):
if not search_term:
return queryset, False
queryset, may_have_duplicates = super().get_search_results(
request, queryset, search_term,
)
search_term_list = search_term.split(' ')
specimen_names = [q.specimen_name for q in queryset.all()]
results = []
for term in search_term_list:
for name in specimen_names:
if term in name:
results.append(name)
break
# Return original queryset, AND any new results we found by searching the specimen_name field
# The True indicates that it's possible that we will end up with duplicates
# I assume that means Django will make sure only unique results are returned when that's set
return queryset + results, True
据我所知,我做不到 queryset.filter(specimen_name=SOMETHING)
. .filter
无法识别 @property
方法作为需要搜索的字段。这就是我编写自己的循环来进行搜索的原因。上面的代码显然不起作用。您不能只将列表添加到查询集中。我将如何返回一个实际的查询集?
最佳答案
过滤属性的正确方法是为该属性制作一个等效的注释,然后对其进行过滤。查看您的属性,它所做的只是连接一些字段,对应于 Django 具有 Concat
database function .因此,您可以进行以下注释:
from django.db.models import Value
from django.db.models.functions import Concat
queryset = queryset.annotate(
specimen_name=Concat("lab_number", Value("_"), "patient_name", Value("_"), "specimen_type")
)
# Note: If you use Django version >=3.2 you can use "alias" instead of "annotate"
然后您可以更改您的get_search_results
如下:from django.db.models import Value, Q
from django.db.models.functions import Concat
from django.utils.text import (
smart_split, unescape_string_literal
)
class SpecimenModelAdmin(admin.ModelAdmin):
...
search_fields = ('patient_name', 'lab_number', 'specimen_type')
def get_search_results(self, request, queryset, search_term):
queryset = queryset.annotate(
specimen_name=Concat(
"lab_number",
Value("_"),
"patient_name",
Value("_"),
"specimen_type"
)
)
queryset, may_have_duplicates = super().get_search_results(request, queryset, search_term)
for bit in smart_split(search_term):
if bit.startswith(('"', "'")) and bit[0] == bit[-1]:
bit = unescape_string_literal(bit)
queryset = queryset.filter(Q(specimen_name__icontains=bit))
return queryset, may_have_duplicates
备注 :除非您设置 search_fields
,否则上述内容可能会停止为您提供结果到一个空的元组/列表。沿着这条线继续下去,也许可以使用注释
specimen_name
在 search_fields
通过覆盖 get_queryset
因此跳过覆盖 get_search_results
:class SpecimenModelAdmin(admin.ModelAdmin):
...
search_fields = ('patient_name', 'lab_number', 'specimen_type', 'specimen_name')
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.annotate(
specimen_name=Concat(
"lab_number",
Value("_"),
"patient_name",
Value("_"),
"specimen_type"
)
)
return qs
关于python - 如何使用自定义搜索字段(模型属性)在 Django Admin 中进行搜索?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69336816/