Django ORM查询获取当前订阅用户的数量
Django ORM Query to get number of currently subbed user
我使用事件日志来跟踪给定邮件列表的订阅和取消订阅。
我的objective是一次访问数据库(sqlite)获取订阅用户数,我不需要对象,只需要一个数字。
models.py
class MailingListEvent(models.Model):
"""Events on mailing lists.
This represents subscribes, unsubscribes, and bounces. We'd like
to understand what happens and when, not just the current state of
the system.
"""
class EventType(models.TextChoices):
SUBSCRIBE = 'sub', 'inscription'
UNSUBSCRIBE = 'unsub', 'désinscription'
BOUNCE = 'bounce', 'bounce'
user = models.ForeignKey(User, on_delete=models.CASCADE)
mailing_list = models.ForeignKey(MailingList,
on_delete=models.CASCADE)
event_timestamp = models.DateTimeField(default=django.utils.timezone.now)
event_type = models.CharField(max_length=6, choices=EventType.choices)
到目前为止,我发现只有这个解决方案可以使用:
def user_subscribe_count(mailing_list):
"""Return the number of users currently subscribed to the mailing list.
We want to know how many users are currently subscribed. Note
that individual users might subscribe and unsubscribe multiple
times. Other (future) events could happen as well.
"""
user_list = MailingListEvent.objects.filter(mailing_list=mailing_list).values_list('user',flat=True).distinct()
users_subscribed = list()
for user in user_list:
user_state = user_current_state(User.objects.get(pk=user),mailing_list)
if user_state.event_type == MailingListEvent.EventType.SUBSCRIBE:
users_subscribed.append(user_state)
return len(users_subscribed)
def user_current_state(user, mailing_list):
"""Return user's most current state on the provided mailing list
Return the most recent event associated with this user in this
mailing list.
"""
try:
the_user = MailingListEvent.objects.filter(
Q(event_type=MailingListEvent.EventType.SUBSCRIBE) |
Q(event_type=MailingListEvent.EventType.UNSUBSCRIBE),
user=user, mailing_list=mailing_list).latest(
'event_timestamp')
return the_user
except MailingListEvent.DoesNotExist:
return MailingListEvent(
user=user, mailing_list=mailing_list,
event_type=MailingListEvent.EventType.UNSUBSCRIBE)
我知道 Django 上有一个 .count() 方法,但是无论如何转换为列表已经访问了数据库。
有人可以建议查询 return 当前订阅该型号的用户数量吗?
您可以使用 Subquery
expression [Django-doc]:
为 MailingList
用最新的 MailingListEvent
注释 User
from django.db.models import OuterRef, Subquery
User.objects.alias(
latest_action=Subquery(
MailingListEvent.objects.filter(
mailing_list=mailing_list,
user=OuterRef('pk')
).order_by('-event_timestamp')<strong>.values('event_type')</strong>[:1]
)
).filter(<strong>latest_action='sub'</strong>).count()
如果最近的操作是BOUNCE
,那么这将不会计为订阅用户。
Note: It is normally better to make use of the settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use the User
model [Django-doc] directly. For more information you can see the referencing the User
model section of the documentation.
Note: Django's DateTimeField
[Django-doc]
has a auto_now_add=…
parameter [Django-doc]
to work with timestamps. This will automatically assign the current datetime
when creating the object, and mark it as non-editable (editable=False
), such
that it does not appear in ModelForm
s by default.
我使用事件日志来跟踪给定邮件列表的订阅和取消订阅。
我的objective是一次访问数据库(sqlite)获取订阅用户数,我不需要对象,只需要一个数字。
models.py
class MailingListEvent(models.Model):
"""Events on mailing lists.
This represents subscribes, unsubscribes, and bounces. We'd like
to understand what happens and when, not just the current state of
the system.
"""
class EventType(models.TextChoices):
SUBSCRIBE = 'sub', 'inscription'
UNSUBSCRIBE = 'unsub', 'désinscription'
BOUNCE = 'bounce', 'bounce'
user = models.ForeignKey(User, on_delete=models.CASCADE)
mailing_list = models.ForeignKey(MailingList,
on_delete=models.CASCADE)
event_timestamp = models.DateTimeField(default=django.utils.timezone.now)
event_type = models.CharField(max_length=6, choices=EventType.choices)
到目前为止,我发现只有这个解决方案可以使用:
def user_subscribe_count(mailing_list):
"""Return the number of users currently subscribed to the mailing list.
We want to know how many users are currently subscribed. Note
that individual users might subscribe and unsubscribe multiple
times. Other (future) events could happen as well.
"""
user_list = MailingListEvent.objects.filter(mailing_list=mailing_list).values_list('user',flat=True).distinct()
users_subscribed = list()
for user in user_list:
user_state = user_current_state(User.objects.get(pk=user),mailing_list)
if user_state.event_type == MailingListEvent.EventType.SUBSCRIBE:
users_subscribed.append(user_state)
return len(users_subscribed)
def user_current_state(user, mailing_list):
"""Return user's most current state on the provided mailing list
Return the most recent event associated with this user in this
mailing list.
"""
try:
the_user = MailingListEvent.objects.filter(
Q(event_type=MailingListEvent.EventType.SUBSCRIBE) |
Q(event_type=MailingListEvent.EventType.UNSUBSCRIBE),
user=user, mailing_list=mailing_list).latest(
'event_timestamp')
return the_user
except MailingListEvent.DoesNotExist:
return MailingListEvent(
user=user, mailing_list=mailing_list,
event_type=MailingListEvent.EventType.UNSUBSCRIBE)
我知道 Django 上有一个 .count() 方法,但是无论如何转换为列表已经访问了数据库。
有人可以建议查询 return 当前订阅该型号的用户数量吗?
您可以使用 Subquery
expression [Django-doc]:
MailingList
用最新的 MailingListEvent
注释 User
from django.db.models import OuterRef, Subquery
User.objects.alias(
latest_action=Subquery(
MailingListEvent.objects.filter(
mailing_list=mailing_list,
user=OuterRef('pk')
).order_by('-event_timestamp')<strong>.values('event_type')</strong>[:1]
)
).filter(<strong>latest_action='sub'</strong>).count()
如果最近的操作是BOUNCE
,那么这将不会计为订阅用户。
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.
Note: Django's
DateTimeField
[Django-doc] has aauto_now_add=…
parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when creating the object, and mark it as non-editable (editable=False
), such that it does not appear inModelForm
s by default.