我在查看时更改字段值的列表,但我想将未更改的值传递给上下文。这里的案例是原始通知系统,在查看通知时,它应该将其状态更改为已查看。
views.py
class Notification(TemplateView):
template_name='myapp/notification.html'
def get_context_data(self, **kwargs):
user = self.request.user
user_unread = user.notification_set.filter(viewed=False)
user_read = user.notification_set.filter(viewed=True)
context = super(Notification, self).get_context_data(**kwargs)
context.update({'user_unread': user_unread, 'user_read': user_read})
for msg in user_unread:
msg.viewed = True
msg.save()
return context
此代码的问题是,我在读取和未读取列表中获得重复值,即使我在更新传递给模板的上下文后已将新值保存到模型中。
模板:
Unread:
<ul>
{% for msg in user_unread %}
<li> {{ msg }} </li>
{% endfor %}
</ul>
Already read:
<ul>
{% for msg in user_read %}
<li> {{ msg }} </li>
{% endfor %}
</ul>
在旁注中,我是CBV的新手,如果我的观察代码可以改进,我会喜欢一些指示。
答案 0 :(得分:1)
这是由于查询集的惰性。在您评估之前,查询集实际上并不会触及数据库,这通常在您进行迭代时发生。因此,在您的代码中,您在视图中迭代user_unread
,以设置读取状态:因此查询集的内容在该点处是固定的。但是,在您到达模板之前,您不会遍历user_read
,因此在此之前不会进行查询,在之后您已更新所有未读通知。
解决此问题的方法是在更新未读取的查询之前,在视图中显式评估读取查询集。您只需在其上调用list
即可完成此操作:
context.update({'user_unread': user_unread, 'user_read': list(user_read)})
for msg in user_unread:
...
答案 1 :(得分:1)
您可以尝试获取另一个重复的查询集来更新对象。使用未更新的模板上下文并仅更新另一个。
像:
def get_context_data(self, **kwargs):
user = self.request.user
user_unread = user.notification_set.filter(viewed=False)
#Do some operation on qs so that it gets evaluated, like
nitems = len(user_unread)
#get another queryset to update
user_unread_toupdate = user.notification_set.filter(viewed=False)
user_read = user.notification_set.filter(viewed=True)
context = super(Notification, self).get_context_data(**kwargs)
context.update({'user_unread': user_unread, 'user_read': user_read})
#Use 2nd queryset
for msg in user_unread_toupdate:
msg.viewed = True
msg.save()
return context
Django会以不同方式缓存每个查询集。因此,一旦评估user_unread
将拥有自己的对象副本。
虽然它不是很优雅/高效,因为加载了类似查询集的多个副本,所以如果记录数量很高,它会更慢。