Django如何将查询公开和私有主题的函数视图改写为ListView类视图
ListView 实现优化说明
你当前的ListView实现是完全可用的,逻辑和原函数视图完全对齐,不存在问题。觉得类视图代码更长是正常的,类视图的核心优势是后续扩展复用(比如要加分页、搜索过滤、权限校验的时候,直接继承对应Mixin或者重写少量方法即可),不是所有场景下代码量都比函数视图少。
更优的写法可以通过Q查询合并查询条件,避免两次查询数据库再合并结果,性能更好,同时可以把排序规则抽到类属性里,代码更简洁:
from django.db.models import Q class TopicsHome(ListView): model = Topic template_name = 'learning_logs/topics.html' context_object_name = 'topics' ordering = ['date_added'] # 排序规则抽为类属性,统一管理 def get_queryset(self): base_query = Q(public=True) # 仅登录用户追加自己的私有主题条件 if self.request.user.is_authenticated: base_query |= Q(owner=self.request.user) return super().get_queryset().filter(base_query)
DetailView 实现修改建议
你目前的代码有两个核心问题需要修正:
- 没有做访问权限校验:未登录用户/非所有者可以通过直接输入slug访问私有主题,不符合业务逻辑
- 上下文里的entries返回了全站所有条目,而非当前主题下的关联条目
修改后的完整参考代码如下:
from django.db.models import Q class ShowTopic(DetailView): model = Topic template_name = 'learning_logs/topic.html' context_object_name = 'topic' slug_url_kwarg = 'topic_slug' def get_queryset(self): # 过滤可访问的主题:要么公开,要么是当前登录用户自己的 base_query = Q(public=True) if self.request.user.is_authenticated: base_query |= Q(owner=self.request.user) return super().get_queryset().filter(base_query) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 只取当前主题关联的条目,如果Entry外键设置了related_name="entries",可以直接写self.object.entries.all() context['entries'] = self.object.entry_set.all() return context
内容的提问来源于stack exchange,提问作者Алексей sk1p
相关产品推荐
相关产品推荐

