Код и отображение словарного списка - каждый ключ является элементом множества, значение - разница между двумя множествами
Приведенный ниже пример прекрасно формулирует мою проблему.
Мои модели:
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>