Как отфильтровать набор запросов Django после его изменения в цикле
Я недавно работаю с Django, и он меня сильно смущает (хотя он мне и нравится).
Проблема, с которой я сталкиваюсь сейчас, заключается в том, что когда я выполняю цикл и в цикле изменяю querryset, в следующем цикле .filter
не работает.
Рассмотрим следующий упрощенный пример:
У меня есть словарь, который создается из набора запросов следующим образом
animal_dict
= {курица: 6,
коровы: 7,
рыба: 1,
овцы: 2}
Кверисет называется self.animals
for key in dict:
if dict[key] < 3:
remove_animal = max(dict, key=dict.get)
remove = self.animals.filter(animal = remove_animal)[-2:]
self.animals = self.animals.difference(remove)
key[replaced_industry] = key[replaced_industry] - 2
Я пытаюсь сделать следующее: моя цель состоит в том, что должен быть баланс между животными. Так как рыб не хватает, 2 животных с наибольшим n должны уйти (коровы). И затем во втором цикле - поскольку не хватает овец, 2 из животных с наибольшим n должны идти снова (курица).
Теперь при первом цикле (с fish) .filter
делает все так, как нужно. Однако, когда я делаю цикл во второй раз (для овец), remove = self.animals.filter(animal = remove_animal)[-2:]
выдает ошибку, не соответствующую фильтру animal =
. Когда я печатаю remove
во втором цикле, он возвращает список всех различных животных (вместо только 1).
После циклов dict
должен выглядеть следующим образом: {курица: 4,
коровы: 5,
рыба: 1,
овца: 2}
Это потому, что сначала корова спустится на 2 и будет max
, а затем курица спустится на 2, так как будет max
Я определенно не понимаю логики Django, но мне это кажется очень странным. Надеюсь, что вопрос понятен, в противном случае буду рад дальнейшим разъяснениям.
Отвечаю на свой собственный вопрос. Очевидно, это не сработало, потому что разрешены только count()
, order_by()
, values()
, values_list()
и нарезка union queryset. Вы не можете фильтровать по union queryset, и то же самое относится к .difference
,
Подробнее об этом здесь: Django: Filter a Queryset made of unions not working
Поскольку во втором цикле он превращается в union queryset, функция фильтрации просто не работает. Странно то, что это не показывает ошибку, а просто не фильтрует, что затрудняет обнаружение.
Как отмечали другие, каждый раз, когда вы вызываете self.animals.filter
, вы делаете запрос к базе данных, и это не должно выполняться в цикле.
Не очень понятно, чего вы пытаетесь достичь, но похоже, что вы хотите, чтобы количество каждого вида животных было (почти?) одинаковым, и что единственная операция, которую вы можете выполнить над ним - это уменьшение количества животных.
Всегда лучше избегать циклов, если это возможно.
Если вы хотите, чтобы их было одинаковое количество, и вы можете только уменьшить количество животных, то лучшим решением будет
fewest_number = min(self.animals.values())
self.animals = {animal: fewest_number for animal in self.animals.keys()}
Если вы хотите, скажем, разрешить допуск +1 от наименьшего количества животных
fewest_number = min(self.animals.values()) + 1
self.animals = {animal: fewest_number for animal in self.animals.keys()}
Если увеличить количество каждого вида животных, то можно найти среднее значение:
average_number = sum(self.animals.values()) / len(self.animals)
self.animals = {animal: average_number for animal in self.animals.keys()}