代码和渲染字典列表 - 每个键都是一个集合的元素,值是两个集合之间的差异

Code and render dictionary list - each key is element of a set, value is difference between two sets

下面的例子完美地阐明了我的问题。

我的模特是:

id  name
1   Alf
2   Beauty

水果

id  name
1   apple
2   banana
3   cape gooseberry
4   date
5   eggplant

饮食

id  person  fruit
1   Alf apple
2   Beauty  apple
3   Alf banana
4   Beauty  cape gooseberry
5   Alf date
6   Beauty  eggplant
7   Alf eggplant
8   Alf apple
9   Beauty  apple
10  Alf banana
11  Beauty  cape gooseberry

(当然,Diet模型中的person和fruit其实就是后台的外键)

必需

没有人没有全水果饮食吗?

如果是这样,输出=字典列表,相应的key/values对是这样的人和his/her饮食

中缺失的水果

如果不是,输出=“None”

我的想法

persons = set(Person.objects.values_list('name', flat=True).order_by('name'))
available_fruit = set(Fruit.objects.values_list('name', flat=True).order_by('name'))
fruit_in_diet = set(Diet.objects.filter(person_id=1).values_list('fruit_id', flat=True).order_by('fruit_id'))
missing_fruit = available_fruit - fruit_in_diet

完成

测试了我的想法并且它有效,分别适用于两个人 - 也就是说,单独。 它仅在我得到一组由代码中使用的每个人的正确 missing_fruits 组成的集合时才有效。

我的问题

我能找到的唯一相关帮助是 Finding set difference between two complex dictionaries,但我的问题从帮助结束的地方开始,如上面的完成中所示。

更新 除了最后一行,上面的代码都有效。

persons = set(Person.objects.values_list('name', flat=True).order_by('name'))
persons
{'Alf', 'Beauty'}
available_fruit = set(Fruit.objects.values_list('name', flat=True).order_by('name'))
available_fruit
{'Banana', 'Cape Gooseberry', 'Date', 'Apple', 'Eggplant'}
fruit_in_diet = set(Diet.objects.filter(person_id=1).values_list('fruit_id', flat=True).order_by('fruit_id'))
fruit_in_diet
{1, 2, 4, 5}

But, the difference between the two sets:
missing_fruit = available_fruit - fruit_in_diet
missing_fruit
{'Banana', 'Cape Gooseberry', 'Date', 'Apple', 'Eggplant'}

Same thing with the 2nd person, the difference between the two sets:
fruit_in_diet = set(Diet.objects.filter(person_id=2).values_list('fruit_id', flat=True).order_by('fruit_id'))
fruit_in_diet
{1, 3, 5}

missing_fruit = available_fruit - fruit_in_diet
missing_fruit
{'Banana', 'Cape Gooseberry', 'Date', 'Apple', 'Eggplant'}

I do not understand why this is happening.
If it could work, I would need help on how to loop over the persons rather than specify them as done in these examples.

只有 missing_fruit 行没有提供预期的答案。

我希望这是我最后一次 post 关于这个问题。 missing_fruit 行不起作用,因为它试图计算一组字符串和一个整数之间的差异。我现在已经为人员和 available_fruit 使用了 id,并且它有效。

代码如下:

persons = set(Person.objects.values_list('id', flat=True).order_by('id'))

人 {1, 2}

available_fruit = set(Fruit.objects.values_list('id', flat=True).order_by('id')) available_fruit {1、2、3、4、5'}

fruit_in_diet = set(Diet.objects.filter(person_id=1).values_list('fruit_id', flat=True).order_by ('fruit_id')) fruit_in_diet {1、2、4、5}

missing_fruit = available_fruit - fruit_in_diet missing_fruit {3}

fruit_in_diet = set(Diet.objects.filter(person_id=2).values_list('fruit_id', flat=True).order_by ('fruit_id')) fruit_in_diet {1, 3, 5}

missing_fruit = available_fruit - fruit_in_diet missing_fruit {2,4}

我希望能够合并显示结果如下

人不见果 阿尔夫海角鹅莓 美女香蕉,枣

有人可以帮我编写代码来进行循环,然后像上面那样显示结果。

为了得到每个人缺少的水果,我们可以使用数据库中 所有 可能的水果列表,并删除每个人存在的每个水果作为 Diet 数据库中的行。

为了能够在 HTML 模板中呈现数据,我们将在 view 中编写缺少水果的逻辑: https://docs.djangoproject.com/en/4.0/intro/tutorial03/

# views.py
from collections import defaultdict
from django.shortcuts import render
from .models import Diet, Fruit, Person

def missing_from_diet_list(request):
    # All of the Fruits in the database
    available_fruit = Fruit.objects.order_by("name")

    # All of the Diet objects in the database, with "Person" and "Fruit" joined in a
    # single query, ordered by each Diet's person_id field.
    diets = Diet.objects.select_related("person", "fruit").order_by("person__name")

    # We can use a collections.defaultdict datatype that starts with the full set of
    # possible fruits and removes any Fruit instances that the Person already has in
    # their Diet.
    missing_fruit_map = defaultdict(lambda: set(available_fruit))
    for diet in diets:
        person = diet.person  # Used as the dictionary key
        fruit = diet.fruit  # Removed from the set of available_fruit for the person
        missing_fruit_map[person].remove(fruit)

    # To make the missing fruit data easier to work with in the template, we'll rebuild
    # the missing_fruit_map object as a list of tuples so that it can be sorted by name.
    for person, fruits in missing_fruit_map.items():
        missing_fruit_map[person] = sorted(fruits, key=lambda fruit: fruit.name)

    missing_fruit_table = sorted(missing_fruit_map.items(), key=lambda item: item[0].name)

    return render(
        request,
        "missing_fruit.html",
        {"missing_fruit_table": missing_fruit_table},
    )

要了解 defaultdict 的工作原理,您可以阅读有关它的更多信息 here in the python documentation

接下来,我们将创建 missing_fruit.html 由我们的视图呈现的文件:

<html>
<head><title>Fruits Missing from People's Diets</title></head>
<body>

    <table>
        <thead>
            <tr>
                <th>Person</th>
                <th>Missing Fruits</th>
            </tr>
        </thead>
        <tbody>
            {% for person, missing_fruits in people_with_missing_fruit.items %}
            <tr>
                <td>{{ person.name }}</td>
                <td>
                    <ol>
                        {% for fruit in missing_fruits %}
                        <li>{{ fruit.name }}</li>
                        {% endfor %}
                    </ol>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

</body>
</html>

正确答案其实连代码都不需要解释。首要任务是找出每个人是否有任何水果没有拿走。

使用 distinct() 并指定 fruit 和 person 字段会产生不同的 person 和 fruit 组合,如果这些组合少于预期,(水果类型 * 人数)则一些水果没有被采摘由某人

https://docs.djangoproject.com/en/4.0/ref/models/querysets/#distinct

幸好我在 PostgreSQL 上!