python - 如何使用自定义搜索字段(模型属性)在 Django Admin 中进行搜索?

标签 python django

这与 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_namesearch_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/

相关文章:

django admin 不会将对象添加到 Manytomany 字段中

python - StringIO 无法识别图像文件错误

python - puffadder( Lombok 的 Python 替代品)没有维护?

python - 跨数据库 SQLAlchemy 应用程序的通用 TEXT/CLOB 数据类型

python - Celery:有没有办法编写自定义 JSON 编码器/解码器?

django - 使用自定义用户模型创建 super 用户后无法登录到 django admin

linux - Django 无法分配给谷歌计算引擎上的 ip 地址

Python HTTP 错误 429 与 urllib2

mysql - 如何连接到 vagrant 中的数据库

python - 缺少所需的参数状态Python社交身份验证电子邮件验证