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.
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.
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: ...
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.
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(*) .
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With