Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django .values_list() alternative that returns a QuerySet for a ForeignKey field's model?

I'm looking for a clean way to convert one type of QuerySet to another based on a models ForeignKey field, so basically something like a .values_list('my_fk', flat=True) but returning a proper QuerySet instead of a values_list() variant.

For example:

class Parent(models.Model):
    child = models.ForeignKey(Child)
    ...

children_qs = Parent.objects.filter(...).theMagicMethod('child')  

Here children_qs should now be a queryset for all Child instances used in the earlier query, instead of a queryset returning Parent instance.

You can sort of do this with a custom queryset and an __in lookup but it feels a bit smelly:

class ParentQuerySet(models.QuerySet):
    ...
    def children(self):
        return Child.objects.filter(id__in=self.values_list('child_id', flat=True))

This takes all the child_id FK's from the records in the Parent's queryset and re-query Child directly. When I inspect the SQL it does a sub query, and I'm not sure if this is optimal or has some odd side effects. It does look like the ordering from the original Parent query is gone, and so are duplicates.

Does anyone got something better then this?

note: I'm aware I could query directly via Child and filter the Parent's fields using the reverse lookup, but that doesn't support everything you can do on the main model.

like image 963
Bartvds Avatar asked Dec 07 '16 13:12

Bartvds


People also ask

Which can be used to retrieve an object directly instead of a QuerySet?

Retrieving Single Objects from QuerySets We can do this using the get() method. The get() returns the single object directly. Let's see the following example. As we can see in both examples, we get the single object not a queryset of a single object.

How do I get QuerySet in Django?

You get a QuerySet by using your model's Manager . Each model has at least one Manager , and it's called objects by default. Access it directly via the model class, like so: >>> Blog.objects <django.db.models.manager.Manager object at ...> >>> b = Blog(name='Foo', tagline='Bar') >>> b.objects Traceback: ...

What does objects all () return in Django?

all() Returns a copy of the current QuerySet (or QuerySet subclass). This can be useful in situations where you might want to pass in either a model manager or a QuerySet and do further filtering on the result. After calling all() on either object, you'll definitely have a QuerySet to work with.

What does a QuerySet return?

A QuerySet is evaluated when you call len() on it. This, as you might expect, returns the length of the result list. Note: If you only need to determine the number of records in the set (and don't need the actual objects), it's much more efficient to handle a count at the database level using SQL's SELECT COUNT(*) .


1 Answers

Try this, it will return query_set of Child class

parent_primary_keys = Parent.objects.filter(...).values_list('pk',flat=True)

 children_qs = Child.objects.filter(id__in=parent_primary_keys)
like image 180
praveen kumar Avatar answered Oct 13 '22 07:10

praveen kumar