Pop method for Django queryset?

I am having a data model where the model contains a members field to relate to objects of the same type. the idea is that each objects can also be a group of objects. Groups can contain groups etc.

class MyObject(CommonModel):
    name = models.CharField(max_length=255, unique=False, null=True, blank=True)
    members = models.ManyToManyField("self", blank=True, symmetrical=False)

For a search with Django-filters I need to perform a recursive search to get all items, but also all parent group items. So I wrote this little helper function that take a query set from a previous search(by name for example) and gives back a queryset that contains all items where one of the items in the querste is in a member.

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

My problem is that there does not seem to be a function to remove an item from a queryset like pop().

You can simplify the implementation like this (using ManyToMany functionality):

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

Here I am keeping the original copy of the queryset, and adding the members queryset to it in a for loop.

As I can see you don't need QuerySet to stay QS. Just change it to list and then use pop() method:

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

You can try it like this:

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

Or this:

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

Note that this implementation may have performance issues if the number of elements in the queryset is large, as the recursive_objects_member_filter function is inherently recursive and could result in a large number of database queries.

Back to Top