通用列表视图引发属性错误:“函数”对象没有属性“_clone”

6 投票
2 回答
6425 浏览
提问于 2025-04-15 21:30

这里出现了一个奇怪的错误,也许有人能帮忙找出问题的根源。这个错误是在尝试扩展Django CMS项目时出现的,涉及到一些我不太明白的逻辑。简单来说,就是:

urls.py
======================
from django.conf.urls.defaults import *
from cmsplugin_flat_news.models import News

'''RETURNING _CLONE ERROR WHEN IMPLEMENTED
def get_news():
    return News.published.all()

news_dict = {
    'queryset': get_news,
}

news_list_dic = {
    'queryset': get_news,
    'paginate_by': 50,
}
'''
# NEXT SECTION FUNCTIONS BUT NEEDS SERVER RESTART TO SEE NEW POSTS.
#CHANGING TO JUST News.published.all RAISES SAME ISSUE AS USING WRAPPER
#SOLUTION ABOVE. SEE: http://docs.djangoproject.com/en/dev/topics/db/queries/#caching-and-querysets
#& EXAMPLE HERE: http://docs.djangoproject.com/en/dev/topics/generic-views/#adding-extra-context

news_dict = {
    'queryset': News.published.all(),
}

news_list_dic = {
    'queryset': News.published.all(),#SAME ISSUE
    'paginate_by': 50,
}

urlpatterns = patterns('django.views.generic.list_detail',
    (r'^$', 'object_list', news_list_dic),
    (r'^(?P<page>[0-9]+)/$', 'object_list', dict(news_list_dic)),
    url(r'^(?P<slug>[-\w]+)/$', 'object_detail', news_dict, name='news_view'),
)

models.py
======================
class PublishedNewsManager(models.Manager):
    #Filters out all unpublished news and news with a publication date in the future
    def get_query_set(self):
        return super(PublishedNewsManager, self).get_query_set() \
                    .filter(is_published=True) \
                    .filter(pub_date__lte=datetime.datetime.now())

class News(models.Model):
    title           = models.CharField(_('Title'), max_length=255)
    slug            = models.SlugField(_('Slug'), unique_for_date='pub_date')
    author          = models.ForeignKey(User)
    description     = models.TextField(_('Description'), blank=True)
    image           = generic.GenericRelation('NewsImage', blank=True, null=True)
    content         = models.TextField(_('Content'), blank=True)
    tags            = TagField()
    is_published    = models.BooleanField(_('Published'), default=False)
    pub_date        = models.DateTimeField(_('Publication date'), default=datetime.datetime.now())
    created         = models.DateTimeField(auto_now_add=True, editable=False)
    updated         = models.DateTimeField(auto_now=True, editable=False)
    published       = PublishedNewsManager()
    objects         = models.Manager()

在评论中可以看到问题:基本上,这是因为我在实现“正确”的解决方案时,想要为视图添加额外的上下文而引发的错误。错误信息是 Attribute Error: "'function' object has no attribute '_clone'"

我尝试使用:News.published.all,而不是 News.published.all(),无论是在包装函数中使用,还是直接在urlpattern的查询集中使用,都会引发这个错误。

我一定是漏掉了什么明显的东西?我觉得可能是因为PublishedNewsManager没有以字典的形式返回对象,或者是需要调整代码以正确返回对象给视图。

2 个回答

0

嗯,我的情况和提问者的不太一样,但我在尝试把一个原始查询集(RawQuerySet)传给通用视图时遇到了一个叫做 _clone 的错误。我用一个比较笨的方法修复了这个错误。

看起来通用视图想做的就是复制这个查询集(可能是为了缓存?),所以我让这个对象返回它自己的一个副本,这样就满足了对 _clone 的调用。

错误信息:

'RawQuerySet' 对象没有 '_clone' 这个属性

代码:

from django.views.generic.list_detail import object_list

....

li_file = File.objects.raw("SELECT * FROM file_file WHERE fn like %s", [search])

#adding this fixed the _clone missing error
def clone(self):
    #return self  - this works as well.
    return copy.copy(self)

li_file.__class__._clone = clone
#end of addition

return object_list(request, 
               queryset = li_file,
               template_name = "file/found.html",
               )        
9

你遇到的 _clone 错误其实是个误导,因为你把一个函数作为参数传给了一个通用视图,而这个视图期待的是一个 QuerySet。你代码中传入 News.published.all() 到通用视图的做法是对的,因为通用视图会尝试克隆它接收到的 QuerySet,这样可以避免缓存第一次查询到的数据(所以当你传入一个函数时就会出错)。

你的问题似乎在于你自定义的 get_query_set 方法返回的是一个根据当前日期和时间过滤的 QuerySet,而这个过滤是在方法被调用时进行的。

我在文档中没有看到关于 filter 参数可以是可调用对象的说明,但我找到了一条 建议 filter 可以接受可调用参数的记录,所以试着修改你的管理器,传入一个函数来获取当前的日期和时间,而不是立即调用它:

class PublishedNewsManager(models.Manager):
    def get_query_set(self):
        return super(PublishedNewsManager, self).get_query_set() \
                    .filter(is_published=True) \
                    .filter(pub_date__lte=datetime.datetime.now)

撰写回答