Поп-метод для Django queryset?
У меня есть модель данных, где модель содержит поле members для связи с объектами одного типа. Идея заключается в том, что каждый объект может быть группой объектов. Группы могут содержать группы и т.д.
class MyObject(CommonModel):
name = models.CharField(max_length=255, unique=False, null=True, blank=True)
members = models.ManyToManyField("self", blank=True, symmetrical=False)
Для поиска с Django-фильтрами мне нужно выполнить рекурсивный поиск, чтобы получить все элементы, а также все элементы родительской группы. Поэтому я написал небольшую вспомогательную функцию, которая принимает набор запросов из предыдущего поиска (например, по имени) и возвращает набор запросов, содержащий все элементы, где один из элементов в наборе запросов входит в группу.
def recursive_objects_member_filter(queryset):
"""Takes a queryset and retruns a queryset of all parent objects"""
query_set_result = []
while queryset:
query_item = queryset.pop()
query_set_result.append(query_item)
members_queryset = MyObject.objects.filter(members=query_item).exclude(id =
query_item.id
)
for member in members_queryset:
queryset.append(member)
return query_set_result
Моя проблема в том, что, похоже, нет функции для удаления элемента из кверисета, подобной pop().
Вы можете упростить реализацию следующим образом (используя функциональность ManyToMany):
def recursive_objects_member_filter(queryset):
"""Takes a queryset and retruns a queryset of all parent objects"""
original_queryset = copy.deepcopy(queryset)
for query_item in queryset:
original_queryset |= MyObject.objects.filter(members=query_item).exclude(id =
query_item.id
)
return original_queryset
Здесь я сохраняю оригинальную копию набора запросов и добавляю к ней набор членов в цикле for.
Как я вижу, вам не нужно QuerySet
, чтобы оставаться QS. Просто измените его на list
и затем используйте метод pop()
:
def recursive_objects_member_filter(queryset):
"""Takes a queryset and retruns a queryset of all parent objects"""
queryset = list(queryset)
query_set_result = []
while queryset:
...
return query_set_result
Вы можете попробовать сделать это следующим образом:
def recursive_objects_member_filter(queryset):
"""Takes a queryset and retruns a queryset of all parent objects"""
query_set_result = []
queryset = list(queryset)
while queryset:
query_item = queryset.pop()
query_set_result.append(query_item)
members_queryset = MyObject.objects.filter(members=query_item)
queryset += list(members_queryset)
return query_set_result
Или так:
def recursive_objects_member_filter(queryset):
"""Takes a queryset and retruns a queryset of all parent objects"""
query_set_result = []
while queryset:
query_item = queryset[0]
query_set_result.append(query_item)
queryset = queryset.exclude(id=query_item.id)
members_queryset = MyObject.objects.filter(members=query_item)
queryset |= members_queryset
return query_set_result
Обратите внимание, что эта реализация может иметь проблемы с производительностью, если количество элементов в наборе запросов велико, поскольку функция recursive_objects_member_filter по своей сути является рекурсивной и может привести к большому количеству запросов к базе данных.