【问题标题】:How to convert function-based views to class based views如何将基于函数的视图转换为基于类的视图
【发布时间】:2019-05-24 09:33:10
【问题描述】:

我有一个基于函数的视图,我正在尝试将其转换为基于类的视图 (DetailView)。基于函数的视图相当于 CBV 中的 DetailView。我该怎么办?

这是基于函数的视图

def show_post(request, post):
    """A View to display a single post.
    The post variable here is the slug to a post.
    The slug to a post may possibly be a duplicate. So we filter all posts by 
    the slug (which is the 1st variable here)
    And then select the first post returned by the filter queryset.
    The first post returned is, of course, the post we are trying to view.
    """
    post = Post.objects.filter(slug=post)
    if post.exists():
        post = post[0]
    else:
        return HttpResponseRedirect('/blog/')
     count_visits = None
    unique_views = set()

    if request.user.is_authenticated:
        post_views = PostView.objects.filter(post=post)
        count_visits = post_views.count()
        for post_view in post_views:
            unique_views.add(post_view.ip)
    else:
        post_view = PostView(post=post, ip=request.META.get('REMOTE_ADDR',''),
                      http_host=request.META.get('HTTP_HOST', ''),
                      http_referrer=request.META.get('HTTP_REFERER',''),                    
                      http_user_agent=request.META.get('HTTP_USER_AGENT', ''),
                             remote_host=request.META.get('REMOTE_HOST', ''))
        post_view.save()

    c = {
        'post': post,
        'comments': comments,
        'new_comment': new_comment,
        'similar_posts': similar_posts,
        'count_visits': count_visits,
        'unique_views': unique_views,
        'comments_count': comments_count,
        'message': message,
    }
    return render(request, 'blog/posts/post.html', c)

然后我尝试使用以下方法将其转换为基于类的视图:

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post.html'
    context_object_name = 'post'

    def get_context_data(self, **kwargs):
        self.slug = get_object_or_404(Post, slug=self.kwargs['slug'])        
        p = Post.objects.filter(slug=self.slug).first()
        if p.exists():
            p = p[0]
        else:
            return HttpResponseRedirect('/blog/')
        count_visits = None
        unique_views = set()

        if self.request.user.is_authenticated:
            post_views = PostView.objects.filter(post=p)
            count_visits = post_views.count()
            for post_view in post_views:
                unique_views.add(post_view.ip)

        else:
            post_view = PostView(ip=self.request.META.get('REMOTE_ADDR', ''),
                 http_host=self.request.META.get('HTTP_HOST', ''),
                 http_referrer=self.request.META.get('HTTP_REFERER', ''),                               
                 http_user_agent=self.request.META.get('HTTP_USER_AGENT', ''),                                 
                 remote_host=self.request.META.get('REMOTE_HOST', ''))

            post_view.save()

        c = {
            'count_visits': count_visits,
            'unique_views': unique_views,
        }

        return render(self.request, self.template_name, c)

我不确定这是解决此问题的正确方法。请帮助我。

非常感谢。

【问题讨论】:

  • get_context_data 方法应该返回 context 字典而不是响应实例。只为return c

标签: python django django-views


【解决方案1】:

默认情况下,DetailView 应该负责传递到您的 url 的 pk/slug,因此您不需要在 get_context_data 的前两行中执行查询集。相信一个更清晰的方法看起来像这样:

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post.html'
    context_object_name = 'post'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.object is None:
            return HttpResponseRedirect(reverse('blog'))

        count_visits = None
        unique_views = set()

        if self.request.user.is_authenticated:
            post_views = PostView.objects.filter(post=self.object)
            count_visits = post_views.count()
            for post_view in post_views:
                unique_views.add(post_view.ip)
        else:
            post_view = PostView.objects.create(
                ip=self.request.META.get('REMOTE_ADDR', ''),
                http_host=self.request.META.get('HTTP_HOST', ''),
                http_referrer=self.request.META.get('HTTP_REFERER', ''),
                http_user_agent=self.request.META.get('HTTP_USER_AGENT', ''),
                remote_host=self.request.META.get('REMOTE_HOST', '')
            )

        context.update({
            'count_visits': count_visits,
            'unique_views': unique_views,
        })

        return context

【讨论】:

  • 仅供参考,最好使用reverse 名称作为网址。 @Toluwalemi 如果 URL 名称 blog 具有模式 /blog/,您可以将 return HttpResponseRedirect('/blog/') 替换为 return HttpResponseRedirect(reverse('blog')。我希望你明白了
  • 不错的收获。谢谢@xxbinxx。我要编辑我的答案。
  • 只是不要忘记解释您所做的每一个更改,否则提问者将无法正确理解。
猜你喜欢
  • 2023-03-06
  • 2021-05-30
  • 1970-01-01
  • 2014-08-07
  • 2013-01-25
  • 1970-01-01
  • 2014-02-16
相关资源
最近更新 更多