javascript - How to filter Highchart plot Data based on Many-to-One relationship?
问题描述
I have this Django
App where I'm showing some data using Highchart (just an example here).
I have two separate views, one where you perform the Filter on the Product
table (among other things), and the other view builds the Json from History
Table to "pass" to the AJAX function for the plot (The real data is quite heavy).
The data is based on a History
table where I have product_id, year, quantity
(I want to show the Quantity over Time).
In my model I also have a table for Products
with products, category
(each product has a category, multiple products can share the same category).
The two tables have a one-to-many relationship with the field product
.
In my template I'd like the user to be able to filter the products
by the category
field (ie: filter products with category 'A'), and this filter should also update the Chart (ie: I want to see the history for just the products in category 'A').
Below my code, I've tried many attempts but none has worked so far.
Please let me know if the code has all the info you need, I've tried to take just the essential.
models.py
class Products(models.Model):
product = models.TextField(primary_key=True)
category = models.TextField(blank=True,null=True)
# ...
class HistoryProducts(models.Model):
product_id = models.ForeignKey(Products)
year = models.TextField(blank=True, null=True)
quantity = models.DecimalFeld(..)
# ...
filters.py
import django_filters
class ProductsFilter(django_filters.FilterSet):
category_contains = CharFilter(field_name='category', lookup_expr='icontains')
class Meta:
model = Products
fields = ['category']
views.py
def index(request):
products = Products.objects.all()
myFilter = ProductsFilter(request.GET, queryset=products)
products = myFilter.qs
# ...
return render(request, 'index.html', context={..})
def chart_data(request):
# maybe here we should filter History by myFilter, but can't find how
# ...
# calculate total quantity
history = HistoryProducts.objects.values('year').order_by('year').annotate(Total=Sum('quantity'))
chart = {
'chart': {'type': 'column'},
'title': {'text': 'Quantity by Year'},
'series': [{
'name': 'Quantity',
'data': list(map(lambda row: {'name': round(row['year']),'y': round(row['Total'])}, history))
}]
}
return JsonResponse(chart)
index.html
<!-- Filter -->
<form method="GET">
{{myFilter.form}}
<button type="submit"> Filter</button>
</form>
<!-- Chart -->
<div>
<div id="container" data-url="{% url 'chart_data' %}"></div>
</div>
<!-- Scripts -->
<script src="https://code.highcharts.com/highcharts.src.js"></script>
<script>
// highchart function
$.ajax({
url: $("#container").attr("data-url"),
dataType: 'json',
success: function (data) {
Highcharts.chart("container", data);
}
});
</script>
I guess my question is: is it possibile to "connect" the same Form Filter built with django-filters
to multiple models?
Or more in general how would someone takle this kind of problem? I'm open to any suggestion. Thanks
EDIT ---
I have found a solution that is not pretty, and also makes the page much slower.
views.py
def index(request):
products = Products.objects.all()
myFilter = ProductsFilter(request.GET, queryset=products)
products = myFilter.qs
# get the id filtered
ids = []
qs = products.values_list('products',flat=True)
for i in qs:
ids.append(i)
# use ids to filter History
history = History.objects.filter(product_id_in=ids).values('year').order_by('year').annotate(Total=Sum('quantity'))
# make the json here
chart = {
'chart': {'type': 'column'},
'title': {'text': 'Quantity by Year'},
'series': [{
'name': 'Quantity',
'data': list(map(lambda row: {'name': round(row['year']),'y': round(row['Total'])}, history))
}]
}
dump = json.dumps(chart)
# return the json to the template
return render(request, 'index.html', context={..})
Now I only need this part in the template:
<script>
Highcharts.chart('container', {{ chart|safe }});
</script>
Basically I moved the Json inside the same view where I filter the data, but this is much much slower.
解决方案
这更像是一个 jQuery/Javascript 问题,但应该可以捕获表单提交,假设您id
为其 HTML 元素分配一个属性,然后使用视图$.getJSON
中GET
的数据chart_data
。
https://api.jquery.com/submit/
例如
// Assuming you assigned id="filter-form" to your form
$('#filter-form').submit(function(event){
event.preventDefault();
var url = $("#container").attr("data-url");
var formData = $('#filter-form').serialize()
$.getJSON(url, formData, function(data){
Highcharts.chart("container", data);
})
});
然后您就可以ProductsFilter
像在request.GET
chart_data
index
def chart_data(request):
products = Products.objects.all()
myFilter = ProductsFilter(request.GET, queryset=products)
products = myFilter.qs
HistoryProducts.objects.filter(
product_id__in=products
).values('year').order_by('year').annotate(
Total=Sum('quantity')
)
chart = {
'chart': {'type': 'column'},
'title': {'text': 'Quantity by Year'},
'series': [{
'name': 'Quantity',
'data': list(map(lambda row: {'name': round(row['year']),'y': round(row['Total'])}, history))
}]
}
return JsonResponse(chart)
推荐阅读
- javascript - 试图更好地理解“可变阴影”
- javascript - 将多个对象的属性共享给一个对象
- anylogic - moveTo on“任务暂停”不起作用
- python - 对 API 的 Python 发布请求
- mobile - Appscript 下拉移动
- laravel - 语法错误,laravel 中的意外标记“<”(查看:/Users/pathparakh/Projects/store/resources/views/product.blade.php)?
- list - Prolog - 我将如何递归地建立一个列表?
- html - Request.body 在第二次发布请求中未定义
- javascript - 在 IIFE 内执行后,函数返回没有返回正确的值
- python - 遍历数据框列表,对每个数据框的某些列执行计算,产生新的结果数据框