创建一个按字段名称分组的列表视图和 link 到详细信息 - django admin

Create a list view with group by field name and link to details - django admin

所以我有以下 table:

class IncomeStatementQuarterly(models.Model):
    date = models.DateField()
    statement = models.CharField(max_length=1000, blank=True, null=True)
    ticker = models.CharField(max_length=1000, blank=True, null=True)
    security = models.ForeignKey(SecuritiesTable, models.DO_NOTHING)
    line_item = models.CharField(max_length=1000, blank=True, null=True)
    amount = models.DecimalField(max_digits=65535, decimal_places=4, blank=True, null=True)

    class Meta:
        ordering=('ticker',)
        verbose_name = "Income statement / Quarterly"
        verbose_name_plural = "Income statements / Quarterly"
        managed = False
        db_table = 'income_statement_quarterly'
        unique_together = (('date', 'ticker', 'line_item'),)

以及我的 admin.py class 中的以下内容:

@admin.register(IncomeStatementQuarterly)
class IncomeStatementQuarterlyAdmin(admin.ModelAdmin):
    
    date_hierarchy = 'date'
    list_filter = ('line_item',)
    list_display = ("ticker", "date", "statement", "line_item", 'amount')
    search_fields = ['ticker']
    list_display_links = ('ticker',)


    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def has_change_permission(self, request, obj=None) -> bool:
        return False

我的目标是创建一个按 'ticker' 和 'date' 字段分组的视图。 截至目前,我的管理视图正在显示我模型的每一行 像这样:

我想按代码和日期重新组合所有内容,这样我就会有一个 link 如果单击它,我将拥有基于给定的日期和代码组合的所有行。

这可能吗?

过去 5 天我一直在到处寻找,我正准备开始一个名为 statements_list 的新模型,该模型由我当前模型的字段(代码、日期)的所有独特组合组成这将有一个主键 link 将其与当前模型(日期、代码)字段的唯一组合

我希望这不会太混乱... 基本上最终结果看起来像这样(基于图片上的可用内容):

您可以通过覆盖 ModelAdmin class 的 get_queryset() 方法并使用 group_by查询.

queryset = IncomeStatementQuarterly.objects.values('date', 'ticker').annotate(max_id=Max('id'))

In mysql raw query like,

SELECT date, ticker, MAX(id) AS "max_id" 
FROM incomestatementquarterly 
GROUP BY date, ticker

但是如果您使用 admin default change_list 模板 那么这个查询会给您一个 error。因为 django admin 在模板中渲染值时期望查询集中的 对象列表 和查询集中的 group_by 查询 return 作为 字典列表.

如果你想使用上面的查询,那么你覆盖change_list模板并渲染数据本身。

另一种解法:

另一种获取相同数据的方法,

覆盖 ModelAdmin 的 get_queryset() 方法 class

您的管理员 class ,

@admin.register(IncomeStatementQuarterly)
class IncomeStatementQuarterlyAdmin(admin.ModelAdmin):
    
    list_display = ("ticker", "date", "view_details")
    ....
    ....
    def get_queryset(self, request):
        max_ids_subquery = IncomeStatementQuarterly.objects.values('date', 'ticker').annotate(max_id=Max('id')).values('max_id')

        queryset = IncomeStatementQuarterly.objects.filter(id__in=max_ids_subquery)

        return queryset

    def view_details(self, obj):
        date = obj.date
        next_date = date + datetime.timedelta(days=1)
        url = ("%s?ticker=%s&date__gte=%s&date__lt=%s") % (reverse('admin:your_app_incomestatementquarterlyproxy_changelist'),obj.ticker, date, next_date)
        return format_html('<a class="button" href="{}">View</a>',url)

在mysql查询中类似,

SELECT * FROM incomestatementquarterly 
WHERE id IN ( SELECT MAX(id) AS "max_id" FROM incomestatementquarterly t1 GROUP BY t1.date, t1.ticker)

您创建了一个代理模型并注册了这个模型,点击查看详细信息您重定向到这个代理模型管理员class,这是确切的 您的模型管理员 class.

class IncomeStatementQuarterlyProxy(IncomeStatementQuarterly):

    class Meta:
        proxy = True

代理模型管理员class

@admin.register(IncomeStatementQuarterlyProxy)
class IncomeStatementQuarterlyProxyAdmin(admin.ModelAdmin):
    
    date_hierarchy = 'date'
    list_filter = ('line_item',)
    list_display = ("ticker", "date", "statement", "line_item", 'amount')
    search_fields = ['ticker']
    list_display_links = ('ticker',)


    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def has_change_permission(self, request, obj=None) -> bool:
        return False