Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic List View raises Attribute Error: "'function' object has no attribute '_clone'

Tags:

python

django

An odd error here, perhaps someone can help track down source as it's attempting to extend the Django CMS project & attempts to use uses some logic written as part of that project which I'm not fully clear on. In short, using:

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()

See issue in comments: basically, error raised by implementing the 'correct' solution to add extra context to the views. Error is Attribute Error: "'function' object has no attribute '_clone'"

Trying: News.published.all instead of News.published.all() raises the error whether used as part of a wrapper function or directly in the queryset part of the urlpattern.

Must be missing something obvious? Think it is to do with the PublishedNewsManager not returning objects as a dictionary, or tweaking the code to correctly return the objects to the view.

like image 878
Chris Avatar asked Apr 12 '10 10:04

Chris


1 Answers

The _clone errors are a red herring caused by you passing a function as an argument to a generic view where a QuerySet is expected. The version of your code which passes News.published.all() to the generic views is correct, as generic views will try to clone the QuerySet they are given, to avoid caching the first lot of data they query for (hence the error when you pass in a function).

Your problem seems to be that your custom get_query_set method is returning a QuerySet filtered based on the current date and time when the method was called.

I can't see anything in the documentation about filter arguments being callable, but I did find this ticket which suggests that filter can take callable arguments, so try changing your manager to pass in the function to be called to get the current date/time, rather than calling it immediately:

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)
like image 169
Jonny Buchanan Avatar answered Sep 19 '22 10:09

Jonny Buchanan