我想使用 Django 框架创建一个新的业务应用程序。关于我可以使用什么作为报告框架有什么建议吗?该应用程序需要生成有关各种业务实体的报告,包括摘要、总计、分组等。基本上,Django/Python 是否有类似水晶报告的等效项?
djangopackages.com 上有一个网格,可能有助于评估选项:
我制作了django-report-builder。它允许您使用 GUI 构建 ORM 查询并生成电子表格报告。它不能做模板,但这将是一个很棒的功能。
根据 @s-lott 的建议,您可以使用代理模型、具有自定义
changelist_view()
的模型管理类以及源自 admin/base_site.html
的自定义模板将报告添加到管理站点。
假设 Django v2.1(用于模型视图权限)和经典的客户、产品和销售域,这是一个完整的示例:
class SalesReport(SalesOrder):
class Meta:
proxy = True
@admin.register(SalesReport)
class SalesReportAdmin(admin.ModelAdmin):
...
def sales_report(self, request):
monthly_products_by_customer_sql = '''
SELECT c.name AS customer,
p.name AS product,
COUNT(DISTINCT o.id) AS total_orders,
SUM(oi.quantity) AS total_products,
SUM(oi.quantity * oi.price) AS total_amount
FROM sales_salesorder o
INNER JOIN customers_customer c ON o.customer_id = c.id
INNER JOIN sales_salesorderitem oi ON o.id = oi.sales_order_id
INNER JOIN products_product p ON oi.product_id = p.id
WHERE o.departure_date >= %s AND o.departure_date <= %s
GROUP BY c.id, p.id
ORDER BY total_amount DESC;
'''
start, end = get_previous_month_start_end_date()
with connection.cursor() as cursor:
cursor.execute(monthly_products_by_customer_sql, (start, end))
results = namedtuplefetchall(cursor)
totals = Totals(
total_orders=sum(r.total_orders for r in results),
total_products=sum(r.total_products for r in results),
total_amount=sum(r.total_amount for r in results),
)
context = dict(
self.admin_site.each_context(request),
title=f'Sales report for {start} - {end}',
period_start=start,
period_end=end,
results=results,
totals=totals,
)
return TemplateResponse(request, 'sales/report.html', context)
changelist_view()
返回报告视图,将其包装到 admin_site.admin_view()
中以防止未经授权的访问
def changelist_view(self, request):
return self.admin_site.admin_view(self.sales_report)(request)
删除添加、更改、删除权限,以便仅保留查看权限并保护更改和历史视图:
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
def change_view(self, *args, **kwargs):
raise PermissionDenied
def history_view(self, *args, **kwargs):
raise PermissionDenied
sales_report()
视图的帮助程序和导入如下:
from collections import namedtuple
from django.core.exceptions import PermissionDenied
from django.db import connection
from django.template.response import TemplateResponse
Totals = namedtuple('Totals', ['total_orders', 'total_products', 'total_amount'])
def namedtuplefetchall(cursor):
'''Return all rows from a cursor as a namedtuple'''
desc = cursor.description
nt_result = namedtuple('Result', [col[0] for col in desc])
return [nt_result(*row) for row in cursor.fetchall()]
def get_previous_month_start_end_date():
today = datetime.date.today()
prev_month_last = datetime.date(today.year, today.month, 1) - datetime.timedelta(1)
prev_month_first = datetime.date(prev_month_last.year, prev_month_last.month, 1)
return prev_month_first, prev_month_last
sales/report.html
(源自 admin/base_site.html
)以使用管理布局:
{% extends "admin/base_site.html" %}
{% block content %}
<div id="content-main"><div class="results">
<table>
<thead>
<tr>
<th scope="col"><div class="text">Customer</div></th>
<th scope="col"><div class="text">Product</div></th>
<th scope="col"><div class="text"># orders</div></th>
<th scope="col"><div class="text"># products</div></th>
<th scope="col"><div class="text">Amount €</div></th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr class="row1">
<td>{{ result.customer }}</td>
<td>{{ result.product }}</td>
<td>{{ result.total_orders }}</td>
<td>{{ result.total_products }}</td>
<td>{{ result.total_amount|floatformat:2 }}</td>
</tr>
{% endfor %}
<tr class="row1" style="font-weight: bold">
<td> </td><td> </td>
<td>{{ totals.total_orders }}</td>
<td>{{ totals.total_products }}</td>
<td>{{ totals.total_amount|floatformat:2 }}</td>
</tr>
</tbody>
</table>
</div></div>
{% endblock %}
现在,该报告将在管理索引页面中列出,并带有仅供查看的图标👁,它受到保护,不会受到未经授权的访问,并且与管理站点的其余部分具有一致的外观。
这些只是具有普通视图功能的 HTML 模板。
这不需要太多:参数来自表单;在视图函数中编写查询,将查询集传递给模板。模板呈现报告。
为什么您需要比这更多的东西?
您可以使用通用列表/详细视图来避免编写大量代码。如果您采用此路线,您可以向通用视图提供查询集和模板,该视图为您处理一些处理。
由于您必须在 Crystal reports 或 Django 中编写查询,因此您并没有真正从“报告”工具中获得太多优势。
编辑 看起来确实两个包都消失了,但现在我们有了一个很好的数据结构,借用自 R——pandas 包中的DataFrame 快速教程(注意“分组”部分)
我不知道 Django(或 Python)的完整报告解决方案,但是无论有没有 ORM,使用 Django 进行报告都非常容易:
就个人而言,我使用 django-tables 和 nore 的 datashaping python 包来快速汇总/平均/中值/IQR/过滤内容,因为我有许多不同的数据源(REST 数据、两个 mysql 数据库、来自 R 的 csv 文件),其中只有很少的它们现在在 django db 中。
Pycha 是我绘制简单图表的候选之一。
我不喜欢客户端基于 ajax 的网格等进行报告,但你也可以将它与 django 模板一起使用。