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

Django筛选最新transaction_type匹配指定值的学生

筛选最新交易类型匹配指定值的学生

需求概述

需要筛选出满足以下条件的学生及其最新交易记录:

  • 每个学生仅保留其**最新(按transaction_date降序)**的交易记录
  • 仅当该最新交易记录的transaction_type等于指定值时,才保留该记录及对应学生

给定Django模型

class Type(models.Model):
    type = models.CharField(max_length=50)

    def __str__(self):
        return self.type  # 注:原代码中return self.durum为笔误,已修正

class Student(models.Model):
    ogr_no = models.CharField(max_length=10, primary_key=True)
    ad = models.CharField(max_length=50)
    soyad = models.CharField(max_length=50)
    bolum = models.CharField(max_length=100,blank=True)
    dogum_yeri = models.CharField(max_length=30)
    sehir = models.CharField(max_length=30)
    ilce = models.CharField(max_length=30)
    telefon = models.CharField(max_length=20,blank=True, null=True)
    nufus_sehir = models.CharField(max_length=30,blank=True, null=True)
    nufus_ilce = models.CharField(max_length=30,blank=True, null=True)

    def __str__(self):
        return  f"{self.ogr_no} {self.ad} {self.soyad}" 

class Transaction(models.Model):
    student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='islemogrenci')
    transaction_type = models.ForeignKey(Type, on_delete=models.CASCADE)
    yardim = models.ForeignKey(Yardim, on_delete=models.CASCADE, blank=True, null=True)
    aciklama = models.CharField(max_length=300,blank=True, null=True)
    transaction_date = models.DateTimeField(blank=True,null=True)
    transaction_user = models.ForeignKey(User, on_delete=models.CASCADE,null=True,blank=True)

    def __str__(self):
        return f"{self.student.ad} {self.transaction_type.type}"  # 同步修正__str__方法

解决方案

方法1:子查询+聚合函数(兼容所有数据库)

先通过子查询获取每个学生的最新交易日期,再关联筛选出对应记录并匹配交易类型:

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

# 第一步:获取目标交易类型实例
target_type = Type.objects.get(type='busy')

# 子查询:计算每个学生的最新交易日期
latest_date_subquery = Transaction.objects.filter(
    student=OuterRef('pk')
).values('student').annotate(
    latest_date=Max('transaction_date')
).values('latest_date')

# 筛选符合条件的交易记录
filtered_transactions = Transaction.objects.filter(
    transaction_date=Subquery(latest_date_subquery),
    transaction_type=target_type
).select_related('student', 'transaction_type')

# 提取对应的学生列表
matched_students = [t.student for t in filtered_transactions]

方法2:PostgreSQL窗口函数(性能更优)

利用PostgreSQL支持的ROW_NUMBER()窗口函数,按学生分组并按交易日期倒序排序,直接取每组第一条(最新)记录后筛选类型:

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

target_type = Type.objects.get(type='busy')

# 用窗口函数标记每个学生的交易记录顺序,最新记录的row_num为1
ranked_transactions = Transaction.objects.annotate(
    row_num=Window(
        expression=RowNumber(),
        partition_by=F('student'),  # 按学生分组
        order_by=F('transaction_date').desc()  # 按交易日期降序排序
    )
).filter(row_num=1, transaction_type=target_type).select_related('student', 'transaction_type')

matched_students = [t.student for t in ranked_transactions]

注意事项

  • 确保transaction_date字段不为空,否则排序逻辑会受影响;若存在空值,可使用Coalesce函数给空值设置一个默认的最早日期:
    from django.db.models.functions import Coalesce
    from django.utils.timezone import make_aware(datetime.min)
    
    # 在窗口函数或聚合时替换空值
    order_by=Coalesce(F('transaction_date'), make_aware(datetime.min)).desc()
    
  • 若需要批量处理或优化查询性能,select_related会预先加载关联的student和transaction_type,避免N+1查询问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 14:25:23