对于在Django / Python中实现的网站,我们有以下要求:
在视图页面上,每个Web分页显示15条消息.如果来自同一来源的更多两条或更多条消息在视图上相互跟随,则应将它们组合在一起.
也许不清楚,但以下例子可能是:
一个例子是(这次在页面上有5条消息):
Message1 Source1
Message2 Source2
Message3 Source2
Message4 Source1
Message5 Source3
...
这应显示为:
Message1 Source1
Message2 Source2 (click here to 1 more message from Source2)
Message4 Source1
Message5 Source3
Message6 Source2
因此,在每个页面上,页面上会显示固定数量的项目,其中一些项目已重新分组.
最佳答案
我没有看到任何好的方法来做你想要直接做的事情.如果您愿意接受一点反规范化,我会建议使用预保存信号将消息标记为头部.
#In your model
head = models.BooleanField(default=True)
#As a signal plugin:
def check_head(sender,**kwargs):
message = kwargs['instance']
if hasattr(message,'no_check_head') and message.no_check_head:
return
prevIoUs_message = Message.objects.filter(time__lt=message.time).order_by('-time')[0]
if message.source == prevIoUs_message.source:
message.head = False
next_message = Message.objects.filter(time__gt=message.time).order_by('time')[0]
if message.source == next_message.source:
next_message.head = False
next_message.no_check_head
next_message.save()
然后你的查询变得非常简单:
messages = Message.objects.filter(head=True).order_by('time')[0:15]
说实话……信号监听器必须比我写的复杂一点.我的方法中存在大量丢失的同步/丢失更新问题,其解决方案将根据您的服务器而有所不同(如果它是单处理的,多线程的,那么python Lock对象应该会让您通过,但是如果它是多处理的,那么你真的需要实现基于文件或数据库对象的锁定).此外,您当然还必须编写相应的删除信号监听器.
显然,这个解决方案涉及添加一些数据库命中,但是它们处于编辑状态而不是视图状态,这对您来说可能是值得的.否则,也许考虑一个更粗糙的方法:抓住30个故事,在视图中循环,敲掉你不会显示的故事,如果剩下15个,则显示它们,否则重复.绝对是一个可怕的最糟糕的情况,但也许不是可怕的平均情况?
如果您的服务器配置使用了多线程的单个进程,则Lock或RLock应该可以解决问题.以下是使用非重入锁定的可能实现:
import thread
lock = thread.allocate_lock()
def check_head(sender,**kwargs):
# This check must come outside the safe zone
# Otherwise,your code will screech to a hault
message = kwargs['instance']
if hasattr(message,'no_check_head') and message.no_check_head:
return
# define safe zone
lock.acquire()
# see code above
....
lock.release()
同样,相应的删除信号也是关键的.
编辑:许多或大多数服务器配置(如Apache)将prefork,这意味着有几个进程正在进行.在这种情况下,上面的代码将毫无用处.有关如何开始与分叉进程同步的想法,请参见this page.