首页 > 解决方案 > Django admin自定义字段按条件获取最新相关对象的结果

问题描述

我有三个模型

class Customer(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    # some other fields, which don't matter

class ActivityStatus(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=5)

class Activities(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    status = models.ForeignKey(ActivityStatus)
    planned_execution_date = models.DateField()

我也有两个在管理员

class CustomerAdmin(admin.ModelAdmin):
    fields = () # doesn't matter really
    list_display() # doesn't matter really

class ActivityAdmin(admin.ModelAdmin):
    fields = () # doesn't matter really
    list_display() # doesn't matter really

我想添加自定义字段 (last_activity_planned_date) 以在 CustomerAdmin 的 changelist_view 上显示和排序。条件如下: - 显示客户最新活动的计划执行日期,但前提是此活动的 status_id = 2。否则不显示

示例 1

客户 1 有 2 个活动 - 最新的有 status_id = 2 和planned_execution_date = 2017-09-17

更改列表视图:

|id|last_activity_planned_date|

|1|2017-09-17|

示例 2

客户 1 有 2 个活动 - 最新的有 status_id = 3 和planned_execution_date = 2017-09-27

|id|last_activity_planned_date|

|1|空|

标签: djangodjango-admindjango-querysetdjango-aggregationdjango-annotate

解决方案


使用这个答案我设法找到了解决方案

from django.db.models.expressions import Subquery, OuterRef
ACTIVITY_STATUS_NEW = 2

def get_queryset(self, request):
    queryset = super().get_queryset(request)
    activities_per_customer = Activities.objects.filter(customer_id=OuterRef('pk'))
    latest_activity_per_customer = (activities_per_customer.order_by('pk', '-created')).distinct('pk')
    latest_active_activity_per_customer =(latest_activity_per_customer.filter(status_id=ACTIVITY_STATUS_NEW))
    queryset = queryset.annotate(_last_activity_planned_date=Subquery(latest_active_activity_per_customer.values('planned_execution_date')[:1]),)

    return queryset

接着

list_display = ('id', 'last_activity_planned_date')

def last_activity_planned_date(self, obj):
    return obj._last_activity_planned_date

last_activity_planned_date.short_description = "Optional description"

推荐阅读