Поп-метод для 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 по своей сути является рекурсивной и может привести к большому количеству запросов к базе данных.

Вернуться на верх