Django 1.7
I have a model:
class Model(models.Model):
tags = models.ManyToManyField(..)
When I do Model.objects.prefetch_related().... it results in many individual queries being issued to fetch the tags, one for each model.
I'd expect 2 queries to happen: 1 to fetch the models, another to fetch the tags for all models.
How to do that?
EDITED:
I'm using a raw query like Model.objects.prefetch_related('tags').raw_query(..)
You should specify a field name to prefetch:
Model.objects.prefetch_related('tags')
If you use the queryset.raw() method then prefetch_related() logic doesn't work.
Related
I'm trying to understand how to get a QuerySet for a nested ManyToMany relationship in Django. Imagine models that look something like this:
class Collection:
...fields...
class Group:
collections = ManyToMany(Collection)
class Account:
groups = ManyToMany(Group)
I can't quite figure out how to query all of the collections for a given account.
E.g. something similar to:
account.groups.all().values('collections')
But the above query gives me a generic QuerySet of just the PKs of the collections, and I'd like a CollectionQuerySet containing the full models.
You can make reverse lookups using lowercase model names (Django docs).
This should give you the QuerySet you're expecting.
Collection.objects.filter(group__account=account)
Be aware that this will likely give you duplicates (e.g. one Collection associated with multiple Groups).
I'm trying to optimise my queries but prefetch_related insists on joining the tables and selecting all the fields even though I only need the list of ids from the relations table.
You can ignore the 4th query. It's not related to the question.
Related Code:
class Contact(models.Model):
...
Groups = models.ManyToManyField(ContactGroup, related_name='contacts')
...
queryset = Contact.objects.all().prefetch_related('Groups')
Django 1.7 added Prefetch objects which let you customise the queryset used when prefetching.
In particular, see only().
In this case, you'd want something like:
queryset = Contact.objects.all().prefetch_related(
Prefetch('Groups', queryset=Group.objects.all().only('id')))
I have a blog model with m2m relationship with a tag object.I want each blog to have multiple sets of tags say [tagset1,tagset2......]. When user submits some sets of tags[usertagset1,usertagset2.....] to retrieve blogs, I have to return all blogs with
usertagset being subset of blog's tagset.
I am not sure of best way to go about it with minimum no. of sql queries.
Should I create a new model that holds the info of blog's tagsets and then have the blog model an m2m relation with this new model?
You can try to filter out tags one by one:
user_tags = [tag1, tag2, ... tagn]
blogs = Blogs.objects.all()
for tag in user_tags:
blogs = blogs.filter(tags=tag) # assuming 'tags' is your M2M field name
Each filter() will narrow your search until only blogs having all specified tags are remaining. Since Django's QuerySets are lazy and can be combined, this will result in a single SQL query.
I'm trying to optimise my app by keeping the number of queries to a minimum... I've noticed I'm getting a lot of extra queries when doing something like this:
class Category(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=127, blank=False)
class Project(models.Model):
categories = models.ManyToMany(Category)
Then later, if I want to retrieve a project and all related categories, I have to do something like this :
{% for category in project.categories.all() %}
Whilst this does what I want it does so in two queries. I was wondering if there was a way of joining the M2M field so I could get the results I need with just one query? I tried this:
def category_list(self):
return self.join(list(self.category))
But it's not working.
Thanks!
Which, whilst does what I want, adds an extra query.
What do you mean by this? Do you want to pick up a Project and its categories using one query?
If you did mean this, then unfortunately there is no mechanism at present to do this without resorting to a custom SQL query. The select_related() mechanism used for foreign keys won't work here either. There is (was?) a Django ticket open for this but it has been closed as "wontfix" by the Django developers.
What you want is not seem to possible because,
In DBMS level, ManyToMany relatin is not possible, so an intermediate table is needed to join tables with ManyToMany relation.
On Django level, for your model definition, django creates an ectra table to create a ManyToMany connection, table is named using your two tables, in this example it will be something like *[app_name]_product_category*, and contains foreignkeys for your two database table.
So, you can not even acces to a field on the table with a manytomany connection via django with a such categories__name relation in your Model filter or get functions.
I'm building an ecommerce website.
I have a Product model that holds info common to all product types:
class Product(models.Model):
name=models.CharField()
description=models.CharField()
categories = models.ManyToManyField(Category)
Then I have SimpleProduct and BundleProduct that have FK to Product and hold info specific to the product type. BundleProduct has a m2m field to other Products.
class SimpleProduct(Product):
some_field=models.CharField()
class BundleProduct(Product):
products = models.ManyToManyField(Product)
When displaying the catalog I'm making one query against the Product model
and then another query per product to get the additional info.
This involve a large number of queries.
I can improve it by using select_related on the simpleproduct and bundleproduct fields.
I can further improve it by using the select_reverse app for m2m fields like categories.
This is a big improvement but there are more required queries because a BundleProduct have several products which can also have relations to other products (configurable product).
Is there a way to have a single query against Product that will retrieve the m2m categories, one2one SimpleProduct and BundleProduct and the BundleProduct's products?
Will this custom query look like a django queryset with all the managers and properties?
Thanks
You can possibly take a look at the extra method of querysets. May give you the opportunity to add some additional fields. But if you want raw queries, you can use the raw method of managers, these will return a type of queryset, that will not however harness the full power of normal querysets but should be enough for your concerns. On that same page the execute method is also shown, this is for truly custom sql that can't even translate into raw querysets.