python Django ORM中的GROUP By用于Django Admin中的页面

lmyy7pcs  于 2022-11-27  发布在  Python
关注(0)|答案(2)|浏览(150)

我在Django的时间不长,很抱歉问了这个可能很愚蠢的问题。但是经过了很多个小时的尝试和大量的互联网搜索,我没有找到一个解决方案。
我的模型:
第一个
OfferViewCount模型的数据库具有以下数据:

id;user_agent;ip_address;created_date;offer_id
24;insomnia/2022.6.0f;127.0.0.1;2022-11-18 14:14:52.501008+00;192
25;insomnia/2022.6.0z;127.0.0.1;2022-11-18 15:03:31.471366+00;192
23;insomnia/2022.6.0;127.0.0.1;2022-11-18 14:14:49.840141+00;193
28;insomnia/2022.6.0;127.0.0.1;2022-11-18 15:04:18.867051+00;195
29;insomnia/2022.6.0;127.0.0.1;2022-11-21 11:33:15.719524+00;195
30;test;127.0.1.1;2022-11-22 19:34:39+00;195

如果我使用Django Admin中的默认输出,如下所示:

class OfferViewCountAdmin(admin.ModelAdmin):
    list_display = ('offer',)

我得到这个:

Offer
offer #192
offer #192
offer #193
offer #195
offer #195
offer #195

我想得到这样一个结果:

Offer;Views
offer #192;2
offer #193;1
offer #195;3

简单地说,我想在admin中显示每个重复帖子的一个示例,并在自定义字段中显示它们的总数。在SQL中,它看起来像这样:

SELECT offer_id, COUNT(*) AS count FROM offer_offerviewcount GROUP BY offer_id ORDER BY COUNT DESC;

我尝试了很多方法,包括覆盖get_queryset。总的来说,我成功地获得了如下所示的预期结果:

class OfferViewCountAdmin(admin.ModelAdmin):
    list_display = ('offer', 'get_views')
    list_filter = ['created_date', 'offer']
    list_per_page = 20

    def get_views(self, obj):
        return OfferViewCount.objects.filter(offer=obj.offer).count()

    def get_queryset(self, request):
        qs = OfferViewCount.objects.filter(
            ~Exists(OfferViewCount.objects.filter(
                Q(offer__lt=OuterRef('offer')) | Q(offer=OuterRef('offer'), pk__lt=OuterRef('pk')),
                offer=OuterRef('offer')
            ))
        )
        
        return qs

    get_views.short_description = _('Views')

但是在这种情况下,按视图排序是不起作用的。如果我通过admin_order_field显式地为get_views添加它,我会得到一个错误,因为数据库中没有这样的字段。为了避免这样的错误,有必要固定覆盖的注解queriset,如下所示:

qs = OfferViewCount.objects.filter(
    ~Exists(OfferViewCount.objects.filter(
        Q(offer__lt=OuterRef('offer')) | Q(offer=OuterRef('offer'), pk__lt=OuterRef('pk')),
        offer=OuterRef('offer')
    ))
).annotate(_views_count=Count('offer'))

并将get_views更改为:

def get_views(self, obj):
    return obj._views_count

但在本例中,Count('offer')始终返回1,这可能是因为此处未分析整个基址。
实际上,请告诉我,如何添加一个工作排序?如果有一些更简单的方法(没有~Exists和结构与Q()|Q())。

zqdjd7g9

zqdjd7g91#

你应该像下面这样使用Django组

def get_queryset(self, request):
    qs = OfferViewCount.objects.values("offer")
    .annotate(count=Count("offer")).distinct().order_by("count")
    return qs
kqlmhetl

kqlmhetl2#

您可以使用下面的queryset进行分组依据查询

from django.db.models import Count

def get_queryset(self, request):
    qs = OfferViewCount.objects.values(
            'offer'
        ).annotate(
            offer_count=Count('id')
        ).order_by("-offer_count")
    return qs

在mysql原始查询中,

SELECT 
`offer_offerviewcount`.`offer_id`, 
COUNT(`offer_offerviewcount`.`id`) AS `offer_count` 
FROM `offer_offerviewcount` 
GROUP BY `offer_offerviewcount`.`offer_id` 
ORDER BY `offer_count` DESC

但是如果你使用admin default change_list模板那么这个查询会给你一个error.因为django admin在呈现模板中的值时期望queryset中的对象列表而group_by查询在queryset中返回dict列表.
如果要使用上述查询,则覆盖change_list模板和呈现数据本身

相关问题