如何基于多对一关系过滤Highchart图数据?

时间:2020-06-29 15:41:45

标签: javascript python jquery django

我有这个Django应用程序,其中我正在使用Highchart显示一些数据(这里只是一个例子)。

我有两个单独的视图,其中一个是在Product表上执行Filter(除其他外),另一个视图是从History表构建Json来“传递”到AJAX绘图功能(实际数据非常繁重)。

数据基于我有 History product_id, year, quantity表(我想显示一段时间内的数量)。

在我的模型中,我还有一个Products products, category 的表格(每个产品都有一个类别,多个产品可以共享同一类别)。

两个表与字段product一对多。

在我的模板中,我希望用户能够通过 products 字段过滤category(即:过滤类别为“ A”的产品),并且此过滤器还应该更新图表(即:我只想查看类别“ A”中的产品的历史记录)。

在我的代码下面,我尝试了许多尝试,但到目前为止都没有成功。

请让我知道代码是否具有所需的所有信息,我已尝试仅提供基本信息。

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>

我猜我的问题是:是否可以将用django-filters构建的同一个表单过滤器“连接”到多个模型?

或更一般而言,有人会如何解决这种问题?我愿意接受任何建议。谢谢

编辑---

我发现了一个不理想的解决方案,并且也使页面运行缓慢。

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={..})

现在我只需要模板中的这一部分:

<script>
  Highcharts.chart('container', {{ chart|safe }});
</script>

基本上,我将Json移到了用于过滤数据的同一视图内,但这要慢得多。

1 个答案:

答案 0 :(得分:4)

更多是关于jQuery / Javascript的问题,但假设您正在为其HTML元素分配id属性,然后对{{1}使用$.getJSON,则应该可以捕获表单提交} GET视图中的数据。

https://api.jquery.com/submit/

例如

chart_data

然后,您将可以像在// 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