You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为GroupCaseFile标注含最新ProceduralAct的字段并实现多字段搜索?

问题需求

我需要在HTML模板的表格中展示GroupCaseFile模型的数据,其中某一列要显示对应最新ProceduralAct对象的act_number、act_type和summary字段(放在同一个单元格里)。

原本可以通过group_case_file.case_file.proceduralact_set.all().order_by('-created_at').first()获取这个最新对象,但现在需要先根据搜索词对最新ProceduralAct的这三个字段进行过滤,再获取符合条件的GroupCaseFile数据。

我试过用嵌套子查询标注summary字段来实现单字段搜索,但想知道能不能标注一个名为last_procedural_act的字段,让它包含对应最新ProceduralAct的查询集,从而实现多字段搜索;同时也希望得到其他可行的实现方案。


模型代码

class CaseFile(models.Model):
    code = models.CharField(primary_key=True, max_length=30)
    # 其他字段

class GroupCaseFile(models.Model):
    id = models.BigAutoField(primary_key=True)
    case_file = models.ForeignKey(
        CaseFile, on_delete=models.CASCADE, default=None)
    group = models.ForeignKey('accounts.Group', on_delete=models.CASCADE)
    client_name = models.CharField(max_length=255, null=True, blank=True)
    # 其他字段

class ProceduralAct(models.Model):
    id = models.BigAutoField(primary_key=True)
    case_file = models.ForeignKey(
        CaseFile, on_delete=models.CASCADE, default=None)
    act_type = models.CharField(max_length=255)
    act_number = models.CharField(max_length=255, null=True)
    summary = models.TextField()
    created_at = models.DateField()

现有视图代码片段

# 获取最新程序性动作的summary的子查询
subquery_procedural_acts_summary = Subquery(
    ProceduralAct.objects.filter(
        casefile=OuterRef('pk')  # 注:原代码字段名错误,应为case_file
    ).order_by('-created_at').values('summary')[:1]
)

# 通过CaseFile关联获取最新summary的子查询
subquery_case_file_last_procedural_act_summary = Subquery(
    CaseFile.objects.annotate(
        last_procedural_act_summary=subquery_procedural_acts_summary
    ).filter(
        groupcasefile=OuterRef('pk')  # 注:原代码关联逻辑错误,需按反向关联调整
    ).values('last_procedural_act_summary')
)

# 给GroupCaseFile标注最新summary字段
group_case_files = GroupCaseFile.objects.annotate(
    last_procedural_act_summary=subquery_case_file_last_procedural_act_summary
) # 待加入搜索过滤逻辑

dashboard_case_files_list = []
for group_case_file in group_case_files:
   # 组装数据传到模板

解决方案

方案一:标注多字段子查询实现数据库层面过滤

无法直接标注包含完整ProceduralAct对象的字段,但可以分别标注最新动作的三个核心字段,既能支持多字段搜索过滤,也能直接在模板中展示:

from django.db.models import OuterRef, Subquery, Q

# 先获取每个CaseFile对应的最新ProceduralAct的ID(通过ID关联取字段更高效)
subquery_latest_pa_id = Subquery(
    ProceduralAct.objects.filter(
        case_file=OuterRef('case_file__pk')  # GroupCaseFile关联CaseFile的主键
    ).order_by('-created_at').values('pk')[:1]
)

# 给GroupCaseFile标注最新动作的三个字段
group_case_files = GroupCaseFile.objects.annotate(
    latest_pa_id=subquery_latest_pa_id,
    latest_pa_act_number=Subquery(
        ProceduralAct.objects.filter(pk=OuterRef('latest_pa_id')).values('act_number')[:1]
    ),
    latest_pa_act_type=Subquery(
        ProceduralAct.objects.filter(pk=OuterRef('latest_pa_id')).values('act_type')[:1]
    ),
    latest_pa_summary=Subquery(
        ProceduralAct.objects.filter(pk=OuterRef('latest_pa_id')).values('summary')[:1]
    )
)

# 多字段搜索过滤示例(search_term为用户输入的关键词)
search_term = request.GET.get('search', '')
if search_term:
    group_case_files = group_case_files.filter(
        Q(latest_pa_act_number__icontains=search_term) |
        Q(latest_pa_act_type__icontains=search_term) |
        Q(latest_pa_summary__icontains=search_term)
    )

# 模板中单个单元格展示方式:
# <td>{{ obj.latest_pa_act_number }} - {{ obj.latest_pa_act_type }}<br>{{ obj.latest_pa_summary }}</td>

方案二:用Window函数+Prefetch优化查询

借助Django的Window函数标记每个CaseFile的最新动作,再通过Prefetch一次性拉取关联数据,适合大数据量场景:

from django.db.models import Window, F, Q
from django.db.models.functions import RowNumber

# 给ProceduralAct按CaseFile分组,按created_at倒序标记行号,只保留每个CaseFile的最新动作
pa_with_row_number = ProceduralAct.objects.annotate(
    row_num=Window(
        expression=RowNumber(),
        partition_by=F('case_file'),
        order_by=F('created_at').desc()
    )
).filter(row_num=1)

# 用Prefetch将GroupCaseFile与最新ProceduralAct关联,避免N+1查询
group_case_files = GroupCaseFile.objects.prefetch_related(
    Prefetch(
        'case_file__proceduralact_set',
        queryset=pa_with_row_number,
        to_attr='latest_procedural_act'
    )
)

# 搜索过滤逻辑
if search_term:
    target_pas = pa_with_row_number.filter(
        Q(act_number__icontains=search_term) |
        Q(act_type__icontains=search_term) |
        Q(summary__icontains=search_term)
    )
    group_case_files = group_case_files.filter(
        case_file__proceduralact__in=target_pas
    ).distinct()  # 去重避免重复匹配

# 模板中展示方式:
# {% for obj in group_case_files %}
# <td>
#   {% with latest_pa=obj.case_file.latest_procedural_act.0 %}
#     {{ latest_pa.act_number }} - {{ latest_pa.act_type }}<br>{{ latest_pa.summary }}
#   {% endwith %}
# </td>
# {% endfor %}

方案三:自定义模型属性(仅适合小数据量)

如果数据量不大,可给GroupCaseFile添加属性直接获取最新动作,但此方式无法在数据库层面过滤,需在内存中处理:

# 在GroupCaseFile模型中添加属性
class GroupCaseFile(models.Model):
    # 原有字段...
    
    @property
    def last_procedural_act(self):
        return self.case_file.proceduralact_set.order_by('-created_at').first()

# 视图中拉取数据并内存过滤
group_case_files = GroupCaseFile.objects.all().select_related('case_file')
if search_term:
    group_case_files = [
        gcf for gcf in group_case_files
        if gcf.last_procedural_act and (
            search_term in (gcf.last_procedural_act.act_number or '') or
            search_term in gcf.last_procedural_act.act_type or
            search_term in gcf.last_procedural_act.summary
        )
    ]

# 模板中直接调用:
# <td>{{ obj.last_procedural_act.act_number }} - {{ obj.last_procedural_act.act_type }}<br>{{ obj.last_procedural_act.summary }}</td>

内容的提问来源于stack exchange,提问作者Rohalt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:01:01