Django запрос для возврата процента пользователей, имеющих сообщение
Две модели Пользователи (встроенные) и Посты:
class Post(models.Model):
post_date = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='user_post')
post = models.CharField(max_length=100)
Я хочу иметь конечную точку API, которая возвращает процент пользователей, разместивших сообщение. В основном мне нужно SUM(уникальные пользователи, которые разместили сообщение) / total_users
Я пытался играть с annotate и aggregate, но я получаю сумму постов для каждого пользователя или сумму пользователей на пост (который один...). Как я могу получить сумму постов, возвращенных уникальными пользователями, разделить ее на user.count и вернуть?
Мне кажется, что я упускаю что-то глупое, но мой мозг превратился в кашу, глядя на это.
class PostParticipationAPIView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get_queryset(self):
start_date = self.request.query_params.get('start_date')
end_date = self.request.query_params.get('end_date')
# How can I take something like this, divide it by User.objects.all().count() * 100, and assign it to something to return as the queryset?
queryset = Post.objects.filter(post_date__gte=start_date, post_date__lte=end_date).distinct('user').count()
return queryset
Моя цель состоит в том, чтобы в итоге получить конечную точку следующего вида:
{ общее_участие: 97.3 }
Спасибо за любое руководство.
BCBB
что-то вроде этого должно работать
# get total user count
total_users = User.objects.count()
# get unique set of users with post
total_users_who_posted = Post.objects.filter(...).distinct("user").count()
# calculate_percentage
percentage = {
"total_participation": (total_users_who_posted*100)/ total_users
}
# take caution of divion by zero
Я не думаю, что возможно использовать djangos orm для этого полностью, но вы можете использовать orm для получения количества пользователей (с постами и общим количеством):
from django.db.models import BooleanField, Case, Count, When, Value
counts = (User
.objects
.annotate(posted=Case(When(user_post__isnull=False,
then=Value(True)),
default=Value(False),
output_field=BooleanField()))
.values('posted')
.aggregate(posted_users=Count('pk', filter=Q(posted=True)),
total_users=Count('pk', filter=Q(posted__isnull=False)))
# This will result in a dict containing the following:
# counts = {'posted_users': ...,
# 'total_users': ....}