'PostListView' object has no attribute 'views'


What I want to do is that an entry has a visit counter but I can not implement it correctly.


class Post(models.Model):
    title = models.CharField(max_length=50)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_date = models.DateTimeField(auto_now_add=True)
    views = models.PositiveIntegerField(default=0)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return 'detail/%s' % self.pk

My problem is in get_context_data () I think, but I do not understand why ListView does not have the attributes of the model .


class PostListView(generic.ListView):
    model = Post
    context_object_name = 'posts'
    template_name = 'home.html'
    queryset = Post.objects.order_by('-created_date')

    def get_context_data(self, **kwargs):
        self.views += 1
        kwargs['views'] = self.views
        return super().get_context_data(**kwargs)

class PostDetailView(generic.DetailView):
    model = Post
    context_object_name = “post”
    template_name = ‘detail.html’

    def get_context_data(self, **kwargs):
        self.views += 1
        #Aqui realmente no se que retornar 

I could make it work with function based views but it's not what I really want, I'd like to be able to do it with CBV.

This is what I want to achieve, but done in the generic class

def post_detail(request, post_pk):
    post = Post.get_object_or_404(Post, pk=post_pk)
    post.views += 1
    return render(request, ‘detail.html’, {‘post’: post }

Sorry if I give little information or the question is wrong, I'm relatively new.

asked by federico 12.12.2018 в 00:02

2 answers


Finally I found a solution, and I was making the mistake of using get_context_data (), I did not need to add data to my PostDetailView, but I needed to make changes after the view was called, and for that django it uses get_object, which is the one that returns the object of the model, and in that method you just have to overwrite what you want to do, in my case increase visits by 1, and then return the modified object.

class PostDetailView(generic.DetailView):
model = Post
template_name = "detail.html"

    def get_object(self):
        post = super().get_object()
        #Aumentar en 1 las visitas
        post.views +=1
        return post

Then in the template use post as context_object_name of the generic class

answered by 14.12.2018 / 18:14

Federico, I think you're a bit confused. The attribute views does not belong to the class of the view, it belongs to the model. With this, the only thing you would have to do in your detail view is:

class PostDetailView(generic.DetailView):
    model = Post
    template_name = "detail.html"

    def get(self, request, *args, **kwargs):
        self.object.views += 1
        # Deja que la clase se encargue de lo demás
        return super(PostDetailView, self).get(request, *args, **kwargs)

When you use a DetailView you have access to the instance in question (the post ) using self.object . I repeat: do not confuse the self , which is the same class, with the self.object that refers to an instance of the model or record in the database.

answered by 14.12.2018 в 16:14