3

我有一个看起来像这样的自定义模型管理器:

class MyManager(models.Manager)
    def get_query_set(self):
        '''Only get items that are 'approved' and have a `pub_date` that is in
        the past.  Ignore the rest.'''
        queryset = super(MyManager, self).get_query_set()
        queryset = queryset.filter(status__in=('a',))
        return queryset.filter(pub_date__lte=datetime.utcnow())

这很好用;但是,我在使用 Django 的generic.list_detail视图时遇到了问题object_detail,并且object_list:查询集似乎只加载了一次,因此,它没有获取应有的项目,因为我认为utcnow()时间只被调用了一次(当它首次加载)。

我认为这是故意的,并且是为了提高性能 - 但是,这意味着视频会先显示在网站的其他地方(在我不在视图中的地方object_detail),然后才能在object_detail视图中使用(请参阅下面的 urls.py)。这导致 404...

有任何想法吗 ?还是我必须编写自己的自定义视图来避免这种情况?

谢谢!

网址.py

url(r'^video/(?P<object_id>\d+)$', 
    list_detail.object_detail,
    {   'queryset': Video.objects.all(), },
    name='video_detail',
),
4

3 回答 3

4

这不是缓存问题:正如您现在所做的那样,查询集定义在解析 url 时被评估一次,然后再也不会被评估。

解决方案实际上非常简单,并在在线文档中进行了描述:使用包装函数进行复杂过滤:只需创建一个小的自定义视图,它将简单地调用通用视图。
我实际上经常使用类似的解决方案,我觉得它很舒服。

顺便说一句,对于这种情况,我建议不要使用自定义管理器,而是返回正常过滤。

于 2009-12-07T00:33:43.203 回答
2

尝试将 urls.py 更正为:

url(r'^video/(?P<object_id>\d+)$', 
    list_detail.object_detail,
    {   'queryset': Video.objects.all, }, # here's the difference
    name='video_detail',
)

编辑:

如果失败,尝试对 filter() 应用类似的技术(传递 callable 而不是调用它):

return queryset.filter(pub_date__lte=datetime.utcnow)
于 2009-12-06T22:29:06.810 回答
1

我有一个与 thornomad 几乎相同的模型管理器,通用视图也有同样的问题。

我必须指出,上述建议都不起作用:

  • 不带括号做 Video.objects.all 会出错
  • 做 queryset.filter(pub_date__lte=datetime.utcnow),再次不带括号,不会给出错误但不能解决问题

我还尝试了另一种方法,即使用 lambda 来返回查询集,例如:

qs = lambda *x: Video.objects.all()
url(r'^video/(?P<object_id>\d+)$', 
    list_detail.object_detail,
    {   'queryset': qs(), },
    name='video_detail',
),

......它也没有工作,我现在可以看到我一定是绝望地认为它会:)

lazy_qs = lambda *x: lazy(Post.live_objects.all, QuerySet)

blog_posts = {
    'queryset': lazy_qs(),

...也不起作用(给出错误),因为 utils.functional.lazy 不知道如何正确地将结果转换为 QuerySet,据我所知。

我认为罗伯托包装通用视图的答案是唯一有帮助的答案。

应该修改 django 文档以指出通用视图使用的查询集的限制(当前文档有一个特别说明告诉你一切都会好起来的!)

于 2010-05-25T15:26:03.353 回答