How to select users and groups in single query in django? - django

I need something like this for selecting user and groups in a single query in django.
user = User.objects.select_related('groups').get(id=user_id)
I don't want to use raw queries for this.
There is another way to do this which makes two queries:
user = User.objects.get(id=user_id)
groups = user.groups

Edit: It seems there is no way to do that in one query except raw sql or extra.
So if you only want to get one user, your second example should work.
If many users:
You should use prefetch-related, but in two queries.
prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related, in addition to the foreign key and one-to-one relationships that are supported by select_related. It also supports prefetching of GenericRelation and GenericForeignKey.
...
The additional queries in prefetch_related() are executed after the QuerySet has begun to be evaluated and the primary query has been executed.
So if you want to prefetch groups, it will execute two queries whether you use all or get.

You can use prefetch related in the view, and then pass it to the template
def view(request):
user = User.objects.all().select_related(
).prefetch_related(
'groups',
).get(pk=request.user.pk)
return render(request, 'app/template.html', {
'user': user,
})

You should select from Group model 'cause the relation is many to many.
I have not tried my answer but perhaps it will work;
group_list_with_user = Group.objects.filter(user = USERID).all()
thereafter you can access all groups which are assigned to user and access user for example;
group_list_with_user[0].name # group name
group_list_with_user[0].user.first_name # user's first name

Related

How to query records from a nested M2M field in Django?

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).

Optimal project organization and querysets

I have 2 models Company and Product with FK on Product:
class Product(Meta):
company = models.ForeignKey(Company, related_name='products', on_delete=models.CASCADE)
In case of a View that will gather company products what is the optimal approach(use infor form both models):
1) add the View in companies app and as queryset use:
Company.objects.prefetch_related('products').get(pk=company_pk)
2) add the View in products app and as queryset use:
Product.objects.select_related('company').filter(company=company_pk)
What about ordering can be chained with prefetch or select ?
The Django docs illustrate the difference quite well:
prefetch_related(*lookups)
Returns a QuerySet that will
automatically retrieve, in a single batch, related objects for each of
the specified lookups.
This has a similar purpose to select_related, in that both are
designed to stop the deluge of database queries that is caused by
accessing related objects, but the strategy is quite different.
select_related works by creating an SQL join and including the fields
of the related object in the SELECT statement. For this reason,
select_related gets the related objects in the same database query.
However, to avoid the much larger result set that would result from
joining across a ‘many’ relationship, select_related is limited to
single-valued relationships - foreign key and one-to-one.
select_related(*fields)
Returns a QuerySet that will “follow” foreign-key relationships,
selecting additional related-object data when it executes its query.
This is a performance booster which results in a single more complex
query but means later use of foreign-key relationships won’t require
database queries.

Fetch multiple rows from multiple models Django

I have this project where, I need to fetch multiple objects from multiple models in a view. I could do that by for loop but I think I shouldn't hit database in each loop. Should I use prefetch_related. or Should I know some other way to retrieve them.
for example:
class A(models.Model):
title_name=models.CharField(...)
id=models.AutoField(pk=True)
class B(models.Model):
user=models.ForeignKey(User,models.ON_CASCADE=True)
user_status=models.CharField(...)
id=models.ForeignKey(A, models.ON_CASCADE=True)
I need to display user_status, user and associated title_name. I get multiple objects, select_related will not be useful. Any suggestions.
You need make this queryset:
B.objects.all().select_related('user', 'id')
This queryset will generate sql that join user and A data from db
Next, in the model B to make a property:
#property
def title_name(self):
return self.id.title_name
Finally you'll get queryset that makes one SQL request to database and returns all data you need.
By the way, I would rename attribute "id" in the model B to "a".

django prefetch_related id only

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')))

Filter across different models by one common field in django

I have the following django model manager:
class EntityManager(models.Manager):
...
def filter(self, uuid, *args, **kwargs):
entity_qs = EmptyQuerySet()
for Model in entity_classes:
count = Model.objects.filter(uuid=uuid, *args, **kwargs).count()
if count:
entity_qs = Model.objects.filter(uuid=uuid, *args, **kwargs)
break
return entity_qs
uuid field is a common field across different models and it is unique across them. Idea of the
code above is to get count of rows for different models and when it is positive then return actual query set that will return necessary instance on evaluation. So in worse cases we will do len(entity_classes) SELECT statements + 1 select on result query set evaluation.
The question is: is it possible to filter across different models by one common field with django orm with more efficient way than i do?
First, to try to answer your question directly: given what you've described, I don't know any way around checking each table. If you index on uuid that will certainly speed up the queries. Also, use exists() instead of count().
But the fact that uuid is unique across all tables might be a sign that you should reorganize your schema. If you can't do away with the idea entirely, consider linking from your user model to a new model that specifies both the table and the primary key of the corresponding row.
Django has a built-in way of doing this: the contenttypes framework. From the documentation:
Adding a foreign key from one of your own models to ContentType allows your model
to effectively tie itself to another model class.... A normal ForeignKey can only
"point to" one other model.... The contenttypes application provides a special field
type (GenericForeignKey) which works around this and allows the relationship to be
with any model.