fantom
fantom

Reputation: 555

Get only certain fields of related object in Django

Say I have such models in Django:

class User(models.Model):
    name=models.CharField(...)
    email=models.EmailField(...)
    photo=...
    <other fields>

class Comment(models.Model):
    user=models.ForeignKey(User, ...)

I have a function that receives Comment object and needs just name and email fields to send email (it is just example, obvious)

def sendEmail(comment):
    name, email=comment.user.name, comment.user.email

In implementation presented above, Django will fetch all fields of related object User (something roughly equal to select * from users where id=comment.user_id) Using values_list I can fetch just needed fields:

Users.objects.filter(id=comment.user_id).values_list('name', 'email')

but values_list only applicable to QuerySet object, not to model instance. My question is: is there any way to do the same thing using only "comment" object? It must be equal to select name, email from users where id=comment.user_id by complexity (I don't want to transfer a lot of data stored in some fields over network when I don't need it)

Upvotes: 20

Views: 24874

Answers (4)

Md Fahad Hossain
Md Fahad Hossain

Reputation: 63

queryset = ModelName.objects.filter().only('realed_obj__field1', 'related_obj__field2')

Upvotes: 2

Otuoma Sanya
Otuoma Sanya

Reputation: 138

Users.objects.filter(id=comment.user_id).values_list('name', 'email').get()

That should do

Upvotes: 1

AKS
AKS

Reputation: 19831

It must be equal to select name, email from users where id=comment.user_id by complexity.

What is really equivalent to this query is what you already have:

Users.objects.filter(id=comment.user_id).values_list('name', 'email')

... but values_list only applicable to QuerySet object, not to model instance.

That is absolutely right. but what you need to consider is that once you have this queryset you can get the first element because with one user id there will just be one user:

name, email = Users.objects.filter(id=comment.user_id).values_list('name', 'email').first()

Upvotes: 0

Ivan
Ivan

Reputation: 6013

If you want to have comments with some additional user data, without having to retrieve whole User objects I believe it's better to fetch additional data when you fetch the comments:

Comment.objects.filter(user=user).values_list('user__name', 'user__email')

Obviously you can fetch other useful Comment fields.

OR:

Comment.objects.filter(user=user).annotate(author_name=F('user__name'),\ 
                                           author_email=F('user__email'))

This still uses the QuerySet API, but both approaches allow you to span relationships to get additional data without extra queries.

Upvotes: 16

Related Questions