Код и отображение словарного списка - каждый ключ является элементом множества, значение - разница между двумя множествами

Приведенный ниже пример прекрасно формулирует мою проблему.

Мои модели:

person

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 на самом деле являются внешними ключами в фоновом режиме)

Требуется

У кого-то из людей не было полноценной фруктовой диеты?

Если да, то выход = список словарей, в котором соответствующие пары ключ/значение являются таким человеком и недостающим фруктом из его/ее рациона

Если нет, вывод = "Нет"

Мое мышление

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 для каждого человека, используемого в коде.

Мои вопросы

  • Как получить на выходе список словарей?
  • Как получить единый список словарей для обоих лиц? Другими словами, как мне перебрать ключи, состоящие из элементов множества И значения, состоящие из разностей множеств?
  • Как отобразить этот список словарей в HTML?

Единственная связанная помощь, которую я смог найти, это Finding set difference between two complex dictionaries, но моя проблема начинается там, где заканчивается эта помощь, как видно из Done выше.

Чтобы получить недостающие фрукты для каждого человека, мы можем использовать список всех возможных фруктов в базе данных и удалить каждый фрукт, существующий для данного человека, как 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, вы можете прочитать больше об этом здесь в документации по python.

Далее мы создадим 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>
Вернуться на верх