Multiple annotate with sum and display data in admin - Django

后端 未结 1 1753
你的背包
你的背包 2021-01-03 06:20

I\'m new to both Django and Python. Currently I\'m trying the Django Admin by doing.

I\'ve three models for a Django app, which are GoodsItem, Sol

相关标签:
1条回答
  • 2021-01-03 06:59

    This is known issue and occurs when we try to combine multiple aggregation, as mentioned in docs.

    As a workaround for this particular problem, we can use Subquery expression. Here is my updated admin.py using Subquery expression in get_queryset method of GoodsItemAdmin.

    from django.contrib import admin
    from django.db.models import Subquery, Sum, OuterRef
    
    from .models import GoodsItem, FinishedGoodsItem, SoldGoodsItem
    
    @admin.register(SoldGoodsItem)
    class SoldGoodsItemAdmin(admin.ModelAdmin):
        fields = ('date', 'goods_item', 'weight')
        list_display = ('date', 'goods_item', 'weight')
    
    @admin.register(FinishedGoodsItem)
    class FinishedGoodsItemAdmin(admin.ModelAdmin):
        fields = ('date', 'goods_item', 'weight')
        list_display = ('date', 'goods_item', 'weight')
    
    @admin.register(GoodsItem)
    class GoodsItemAdmin(admin.ModelAdmin):
        list_display = ('__str__', 'finished_good', 'sold_good', 'stock_available')
    
        def get_queryset(self, request):
            qs = super(GoodsItemAdmin, self).get_queryset(request)
            qs = qs.annotate(
                finished_good = Subquery(FinishedGoodsItem.objects.filter(goods_item=OuterRef('pk'))\
                    .values('goods_item_id').annotate(sum=Sum('weight')).values('sum')[:1]),
                sold_good = Subquery(SoldGoodsItem.objects.filter(goods_item=OuterRef('pk'))\
                    .values('goods_item_id').annotate(sum=Sum('weight')).values('sum')[:1])
            )
            return qs
    
        def finished_good(self, obj):
            return obj.finished_good
    
        def sold_good(self, obj):
            return obj.sold_good
    
        def stock_available(self, obj):
            finished_good = 0 if self.finished_good(obj) is None else self.finished_good(obj)
            sold_good = 0 if self.sold_good(obj) is None else self.sold_good(obj)
            return '-' if (finished_good == 0 and sold_good == 0) else finished_good - sold_good
    

    Hope someone finds this useful.

    0 讨论(0)
提交回复
热议问题