0

Following is my model:

class Story(models.Model):
    author = models.ForeignKey(User, related_name='author_id', default=1)
    source = models.ForeignKey(User, related_name='source_id', default=2)

User is the django provided model.

Now I need to find out number of articles authored and sourced by each user.

I thought of using story_set with user object:

res = User.objects.annotate(Count('story_set'))

However, there are two columns in story referencing User. Hence, Django won't know which one to use?

Can anyone help me on this?

3 Answers 3

1

story_set doesn't exist one way or another. That would've been the default related_name if you hadn't provided one. Since you did, you have to use those.

res = User.objects.annotate(Count('author_id'))

OR

res = User.objects.annotate(Count('source_id'))

So, that's how Django knows the difference.

FYI: if you had used the default (so you accessed stories via .story_set.all(), you don't use the "_set" part in queries. It would just be Count('story').

Sign up to request clarification or add additional context in comments.

2 Comments

My doubt is how will Django know about author_id attribute if it doesn't exist in User. It exists in Story.
That's what related_name does. It defines the relationship on the opposite site. If Story has users then User has story_set. Or, in your case, author_id and source_id (which is why you should change those to something more meaningful like author_set and source_set). This is the magic of Django.
1

the reason django makes you specify a related_name is exactly for this reason. you want Count('author_id') instead of Count('story_set') (and you should probably give these better names, e.g. author_set)

Comments

0
res = User.objects.annotate(num_authored=Count('author_id')).annotate(num_sourced=Count('source_id'))
res[0].num_authored
res[0].num_sourced

If you want both the number of authored and number of sourced articles in one query. You might want more appropriate related names, like "authored" and "sourced".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.