0

In this particular case ModelA is the default Django models.User

ModelB is implemented as :

class ModelB(models.Model):
    user = models.ManyToManyField(User)
    #some other stuff

1. For each ModelB record, count the User records which don't have a relationship with it

I managed to do that using :

ModelB.objects.all().annotate(user_count=User.objects.count()-Count('user'))

It works but feels like a hack. Is there a better way to do this (while still using annotate()) ?

2. With filtering

I modified my previous query to be filtered with the currently logged in User so I can display custom content for each user. I intended to keep the same user_count value as in query #1 regardless of the logged in user:

ModelB.objects.filter(
    user=request.user
).annotate(
    user_count=User.objects.count()-Count('user')
)

EDIT : Filtering works as expected when it's done after annotate :

ModelB.objects.annotate(
    user_count=User.objects.count()-Count('user')
).filter(
    user=request.user
)

Still looking for something better than User.objects.count()-Count('user') to count non-related user records for each ModelB record.

Thanks for helping !

nonesk
  • 25
  • 5

1 Answers1

0

I don't think your code is doing what you think it's doing. Count('user') doesn't return the total number of users in the database but only the number of related users to that ModelB object. To use this solution (that you said yourself - is a pretty bad way to do it IMO), you should probably be using User.objects.count().

If I understand your wishes correctly, then this approach should give you the number you seek:

User.objects.filter(modelb_set__isnull=True).count() # "modelb_set" is the default Django related name, if you've set another one, use that.
# or (depending on which you want)
ModelB.objects.filter(user__isnull=True).count()
wanaryytel
  • 3,352
  • 2
  • 18
  • 26
  • @nonesk Is it what you wanted or did I misunderstand something? – wanaryytel Oct 23 '16 at 14:19
  • Sorry my previous comment was a mistake. I'm aware `Count('user')` is about the number of related users to `ModelB`. What I'm trying to do is get the number of **non-related** users to ModelB, and `annotate()` it to my `ModelB` queryset. I did try the solutions you suggested but I couldn't manage to make it work with `annotate`. – nonesk Oct 23 '16 at 14:22
  • @nonesk It seems to me that your approach is warped because annotation is by definition meant for measures that are somehow related to the objects that you're annotating them to. It just doesn't make sense to annotate a random integer (at this point, the number on unrelated users) to every model instance since the number is always the same, a constant. Can you explain what the end goal is and then I can perhaps help you a bit further? – wanaryytel Oct 25 '16 at 20:50