Создание представления списка с группировкой по имени поля и ссылкой на детали - django admin
Итак, у меня есть следующая таблица:
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:
@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'. На данный момент, мое представление администратора отображает каждую строку моей модели следующим образом:
Я хочу перегруппировать все по тикеру и дате так, чтобы у меня была ссылка, при нажатии на которую у меня будут все строки, основанные на заданной комбинации даты и тикера.
Возможно ли это?
Я искал везде последние 5 дней и готовился создать новую модель statements_list, состоящую из всех уникальных комбинаций полей (тикер, дата) моей текущей модели, которая будет иметь первичный ключ, связывающий ее с уникальной комбинацией полей текущей модели (дата, тикер)
Надеюсь, это не слишком запутанно... В основном конечный результат будет выглядеть примерно так (исходя из того, что доступно на картинке):
- A | Jan 31, 2005 ---> ссылка на все заявления с этими параметрами
- A | Apr 30, 2005 ---> ссылка на все утверждения с этими параметрами
Вы можете реализовать это, переопределив метод get_queryset() класса ModelAdmin и используя 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 template, то этот запрос выдает error. Потому что django admin при выводе значений в шаблоне ожидает список объектов в наборе запросов, а group_by запрос возвращает в наборе запросов список dict.
Если вы хотите использовать приведенный выше запрос, то вы переопределяете шаблон change_list и выводите данные самостоятельно.
Другое решение:
Еще один способ получить те же данные,
Override get_queryset() метод класса ModelAdmin
Ваш класс администратора,
@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):
url = ("%s?ticker=%s&date=%s") % (reverse('admin:your_app_incomestatementquarterlyproxy_changelist'),obj.ticker, obj.date)
return format_html('<a class="button" href="{}">View</a>',url)
В mysql запрос simiral to,
SELECT * FROM incomestatementquarterly
WHERE id IN ( SELECT MAX(id) AS "max_id" FROM incomestatementquarterly t1 GROUP BY t1.date, t1.ticker)
вы создаете прокси модель и регистрируете эту модель, при нажатии view details вы перенаправляетесь на этот класс администратора прокси модели, который является точным классом администратора вашей модели.
class IncomeStatementQuarterlyProxy(IncomeStatementQuarterly):
class Meta:
proxy = True
класс администратора прокси-модели
@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