【问题标题】:How to write a query to get the number of times a choice is selected by users如何编写查询以获取用户选择选项的次数
【发布时间】:2020-07-22 01:18:27
【问题描述】:

我想计算用户选择某个选项的次数。这是我的模型

models.py

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from multiselectfield import MultiSelectField


class MedicalHistory(models.Model):
    Anxiety = 'Anxiety'
    Arthritis = 'Arthritis'
    Asthma = 'Asthma'
    Anemia = 'Anemia'
    Cancer = 'Cancer'
    Corona_virus = 'Corona_virus'
    Diabetes = 'Diabetes'
    Ebola = 'Ebola'
    HIV = 'HIV'
    ILLNESS_CHOICES = (
        (Anxiety, "Anxiety"),
        (Arthritis, "Arthritis"),
        (Asthma, "Asthma"),
        (Anemia, "Anemia"),
        (Cancer, "Cancer"),
        (Corona_virus, "Corona_virus"),
        (Diabetes, "Diabetes"),
        (Ebola, "Ebola"),
        (HIV, "HIV"),
    )
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    illness = MultiSelectField(choices=ILLNESS_CHOICES, max_length=50)
    symptoms = models.CharField(max_length=100)
    additional_info = models.CharField(max_length=100)
    disability = models.BooleanField(default=False)
    medications = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return f'{self.user.username} Medical History'

在这里,我希望用户从中选择一些疾病。用户可以选择更多的一种疾病。我希望每种疾病都有一个计数,每次选择疾病时都会增加计数。在我看来,我有

views.py

def pie_chart(request):
labels = []
data = []

queryset = MedicalHistory.objects.values('illness').annotate(count=Sum('user')).order_by('-count')
for entry in queryset:
    labels.append(entry['illness'])
    data.append(entry['count'])

    return JsonResponse(data={
        'labels': labels,
        'data': data,
    }) 

<QuerySet [{'illness': ['Asthma', 'Diabetes', 'Ebola'], 'count': 3}, {'illness': ['Anemia', 'Covid-19'], 'count': 2}]>

查询没有做我想要的,因为我试图在图表中绘制它。由于values,它将我认为的疾病分组。我的 template.html 是这样的。

chart.html

{% block content %}
{% include 'sidebar.html' %}
<div id="container" style="width: 85%;">
    <canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
<script>
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: {{ labels|safe }},
        datasets: [{
            label: 'Overview of Medical History',
            data: {{ data|safe }},
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(225, 400, 64, 0.2)'

            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'

            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
});
</script>

        </div>
     <!-- /#page-content-wrapper -->
</div>
  <!-- /#wrapper -->
{% endblock %}

解决方案:

所以我能够使用 python 解决这个问题。我用疾病初始化了一个字典,并将它们的初始计数设置为 0。然后我使用 values() 返回保存在数据库中的疾病字典。 I 遍历查询集并将 1 连接到疾病的值。然后我将键和值分别作为标签和数据传递。

views.py

def pie_chart(request):
    count = {'Anxiety': 0, 'Arthritis': 0, 'Asthma': 0, 'Anemia': 0, 'Cancer': 0,
             'Corona_virus': 0, 'Diabetes': 0, 'Ebola': 0, 'HIV': 0
             }

    queryset = MedicalHistory.objects.values('illness')
    for entry in queryset:
        for values in entry['illness']:
            count[values] += 1

    labels = [*count.keys()]
    data = [*count.values()]

    return render(request, 'chart.html', {
        'labels': labels,
        'data': data,
    })

【问题讨论】:

    标签: django python-3.x django-models chart.js django-queryset


    【解决方案1】:

    如果您使用的是MultiSelectField,则无法在数据库级别执行此操作,因为基础值只是作为CharField 存储在数据库中。所以values('illness') 只会按 equal 字符串分组,即疾病的组合。

    因此,在获取所有实例之后,要么在 python 中执行此操作:初始化计数器的字典,遍历查询集中的实例并逐个更新计数器。注意:当您的表中 MedicalHistory 的行数变大时,这将无法扩展。

    或将您的Illness 建模为单独的模型(不要使用MultiSelectField),使用ManyToMany 关系并计算它们。然后您可以在查询集中执行此操作。这将随着非常多的行进行扩展。

    【讨论】:

    • 哦,有道理。我可以通过初始化带有疾病的字典来做到这一点。谢谢
    • python 解决方案的问题在于它不能很好地扩展。如果您有数百万个条目,则需要您首先获取内存中的所有条目。而且会很慢。
    • 是的。也因为它可以让您通过管理站点添加新疾病来动态添加它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 2012-09-12
    • 2022-11-10
    • 2018-09-06
    • 2020-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多