单独注释 Django 查询集中的每个项目
目标
我试图获取一个查询集,告诉我用户是否订阅了给定的邮件列表,并能够使用 mailing_list.is_subbed 访问该 bool
理想情况下,我们将有一个查询集,其中每个项目都有一个带注释的字段“is_subbed”为 True
或 False
。
上下文
对于上下文,此视图将提供一个带有复选框的表单,这些复选框根据用户的状态进行选中/取消选中。 该页面可通过包含令牌的 url 以隐身模式访问,该令牌包含 1) 用户的电子邮件和 2) 邮件发送记录的 ID(其中包含发送到的邮件列表等详细信息,详细信息如下
)
在当前状态下, is_subbed 函数仅在第一个项目上调用一次,并且生成的 bool 被注释到每个项目,我希望它为查询集中的每个项目运行。
我怎样才能做到这一点?目前,如果第一个项目在输入到 is_subbed
后返回 True
,则每个复选框都会被标记,因为每个项目上的带注释字段 is_subbed
都设置为 True 。
代码
这是我当前的工作: 摘要:
- 视图
- 在所述视图片段中使用的
- 函数和模型的实现,我用它来访问 jinja2
views.py
class PressSubscriptionManagementView(TemplateView):
template_name = "mailing_list/press_subscription_management.html"
def is_subbed(self, user: User, mailing_list: MailingList) -> bool:
"""
Check if the user is subbed to the mailing list
"""
return user_current_state(user, mailing_list).event_type == "sub"
def get_context_data(self, **kwargs) -> dict:
context = super().get_context_data(**kwargs)
email, send_record_id = token_valid(kwargs["token"])
if email and send_record_id:
context["user"] = User.objects.get(email=email)
# In the current state, is_subbed is only called once on the first
# item in the list. If this call returns True, every checkbox is
# checked. None otherwise.
context["press_subscription_list"] = \
def get_context_data(self, **kwargs) -> dict:
context = super().get_context_data(**kwargs)
email, send_record_id = token_valid(kwargs["token"])
if email and send_record_id:
context["user"] = User.objects.get(email=email)
# In the current state, is_subbed is only called once on the first
# item in the list. If this call returns True, every checkbox is
# checked. None otherwise.
context["press_subscription_list"] = \
MailingList.objects.filter(
mailing_list_type="PR"
).order_by("-id"
).annotate( # noqa
is_subbed=(
ExpressionWrapper(
Value(
self.is_subbed(
context["user"],
F('mailing_list__id')
),
output_field=BooleanField()
),
output_field=BooleanField()
)
)
)
return context
中的结果user_current_state 的实现:
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)
MailingList 和 MailingListEvent 的实现:
class MailingListEvent(models.Model):
class EventType(models.TextChoices):
SUBSCRIBE = 'sub', 'inscription'
UNSUBSCRIBE = 'unsub', 'désinscription'
user = models.ForeignKey(User, on_delete=models.CASCADE)
mailing_list = models.ForeignKey(MailingList,
on_delete=models.CASCADE)
class MailingList(models.Model):
# This is a user-visible name that can change.
mailing_list_name = models.CharField(max_length=80, blank=False)
# This is the unique name that can't change. It just makes code a
# bit more readable than referring to the pk id.
mailing_list_token = models.CharField(max_length=80, blank=False,
unique=True)
SendRecord 的实现:
class TopicBlogEmailSendRecord(models.Model):
slug = models.SlugField(max_length=90, allow_unicode=True, blank=True)
mailinglist = models.ForeignKey(MailingList, on_delete=models.PROTECT)
recipient = models.ForeignKey(User, on_delete=models.PROTECT)
最后是 模板,我像这样访问值:
{% for mailing_list in press_subscription_list %}
[...]
<input type="checkbox" name="{{ mailing_list.mailing_list_name }}"
value="{{ mailing_list.id }}" id="mailing_list_id_{{ mailing_list.id }}"
{% if mailing_list.is_subbed %} checked {% endif %} />
[...]
{% endfor %}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用 subquery ,与a 有条件的表达。
例如,类似的内容:
注意:
mailinglistevent
模型定义event_type
和event_timestamp
fields(从示例中丢失)。何时(最新_EVENT_TYPE ='sub',...
,但是您可能应该使用mailinglistevent.eventtype.subscribe
而不是'sub'sub'<< /代码>。
Instead of your
is_subbed()
method, you could use a Subquery, combined with a conditional expression.For example, something like this:
Notes:
MailingListEvent
model definesevent_type
andevent_timestamp
fields (which are missing from your example).When(latest_event_type='sub', ...
, but you should probably useMailingListEvent.EventType.SUBSCRIBE
instead of'sub'
.