【问题标题】:How to filter Highchart plot Data based on Many-to-One relationship?如何根据多对一关系过滤 Highchart 绘图数据?
【发布时间】:2020-06-29 15:41:45
【问题描述】:

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

我有两个单独的视图,一个是在 Product 表上执行过滤器(除其他外),另一个视图从 History 表构建 Json 以“传递”到绘图的 AJAX 函数(真实数据相当沉重)。

数据基于我有 product_id, year, quantityHistory 表(我想显示随时间变化的数量)。

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

这两个表与字段product是一对多的关系。

在我的模板中,我希望用户能够通过 category 字段过滤products(即:过滤类别为“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 移到了过滤数据的同一视图中,但这要慢得多。

【问题讨论】:

  • 我开始了赏金,因为我没有找到任何与此相关的东西,这似乎是一个典型的场景(其他人可能会觉得这很有帮助)。如果问题不清楚或缺少一些关键信息,请告诉我,以便我改进。

标签: javascript python jquery django


【解决方案1】:

这更像是一个 jQuery/Javascript 问题,但应该可以捕获表单提交,假设您将 id 属性分配给其 HTML 元素,然后使用 $.getJSONGET 来自 @ 的数据987654325@查看。

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);
  })
});

然后您就可以在您的chart_data 中使用来自request.GETProductsFilter,就像您在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)

【讨论】:

  • 感谢您的回答,现在它几乎可以工作了。但是当页面第一次加载时,情节没有显示,只有在我从表单发出请求之后。是否可以修复此问题,以便即使没有制作过滤器也能显示绘图?
  • index() 内,我有一个Products 的计数,在您发出过滤请求后可用,但现在它不起作用。 ProductsFilter 里面的index 好像坏了,你知道问题所在吗?
  • 老实说,我没有标记这个 jQuery/JS,因为起初我想看看是否有“Django”解决方案..对我来说主要问题是使用表中的过滤器过滤其他相关但不在同一视图中的表。 (对不起,三重评论)
  • > 是否可以修复此问题,以便即使没有制作过滤器也能显示绘图?如果您保留初始的 &lt;script&gt; 或添加一个确实请求通过序列化表单来检索 JSON 的 $(function(){}),它当然应该仍然加载。
  • 我不明白为什么我们要过滤产品而不是 HistoryProducts。除了命名约定和缺少索引之外,您只需 HistoryProducts.objects.filter(product_id__category__icontains=value)
猜你喜欢
  • 2018-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-18
  • 2011-02-01
  • 1970-01-01
  • 2021-04-03
  • 2020-01-24
相关资源
最近更新 更多