Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Filter a Queryset made of unions not working

Tags:

python

django

I defined 3 models related with M2M relationsships

class Suite(models.Model):
    name = models.CharField(max_length=250)
    title = models.CharField(max_length=250)
    icon = models.CharField(max_length=250)

    def __str__(self):
        return self.title



class Role(models.Model):
    name = models.CharField(max_length=250)
    title = models.CharField(max_length=250)
    suites = models.ManyToManyField(Suite)
    services = models.ManyToManyField(Service)
    Actions = models.ManyToManyField(Action)
    users = models.ManyToManyField(User)

    def __str__(self):
        return self.title

In one of my views I tried to collect all the Suites related to an specific User. The user may be related to several Roles that can contain many Suites. And then filter Suites by name. But the filter seem to have no effects

queryset = Suite.objects.union(*(role.suites.all() for role in 
self.get_user().role_set.all()))
repr(self.queryset)

'<QuerySet [<Suite: energia>, <Suite: waste 4 thing>]>'

self.queryset = self.queryset.filter(name="energia")
repr(self.queryset)

'<QuerySet [<Suite: energia>, <Suite: waste 4 thing>]>'

The query atribute inside the queryset not alter its content before executin the filter:

(SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite") UNION (SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite" INNER JOIN "navbar_role_suites" ON ("navbar_suite"."id" = "navbar_role_suites"."suite_id") WHERE "navbar_role_suites"."role_id" = 1)

(SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite") UNION (SELECT "navbar_suite"."id", "navbar_suite"."name", "navbar_suite"."title", "navbar_suite"."icon" FROM "navbar_suite" INNER JOIN "navbar_role_suites" ON ("navbar_suite"."id" = "navbar_role_suites"."suite_id") WHERE "navbar_role_suites"."role_id" = 1)
like image 466
Nasgar Avatar asked Mar 13 '18 15:03

Nasgar


People also ask

Can I filter a QuerySet django?

With the Django QuerySet class, you can apply filters that return QuerySets defined by your filters. The filter() method returns all objects that match the keyword arguments given to the method.

How do I do a not equal in django QuerySet filtering?

To answer your specific question, there is no "not equal to" but that's probably because django has both "filter" and "exclude" methods available so you can always just switch the logic round to get the desired result.

Is django QuerySet lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.

What is the purpose of filter () method in django?

The filter() method is used to filter you search, and allows you to return only the rows that matches the search term.


1 Answers

As stated in django docs, only count(), order_by(), values(), values_list() and slicing of union queryset is allowed. You can't filter on union queryset.

That means, you have to apply filters on queries before applying union on them.

Also, you can achieve your goal without even using union():

Suite.objects.filter(role_set__users=self.get_user(), name="energia")

You may need to adjust field name in filter if you've used related_name or related_query_name in definition of suites M2M field in Role model.

like image 61
GwynBleidD Avatar answered Oct 18 '22 17:10

GwynBleidD