Django3环境下django-mptt如何实现符合层级路径的get_absolute_url?
实现步骤
1. 新增模型方法,生成完整层级路径
在你的Category模型中新增两个方法,用于生成完整路径和跳转链接:
class Category(MPTTModel): title = models.CharField(max_length=255, verbose_name=_('Заголовок')) slug = models.SlugField(max_length=255, verbose_name=_('URL'), blank=True) parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True, on_delete=models.CASCADE) class MPTTMeta: order_insertion_by = ['title'] class Meta: unique_together = ['parent', 'slug'] verbose_name = _('Категория') verbose_name_plural = _('Категории') # 新增部分开始 def get_full_slug(self): # 获取从根分类到当前分类的所有slug,拼接为完整路径 slug_list = [item.slug for item in self.get_ancestors(include_self=True)] return "/".join(slug_list) def get_absolute_url(self): # 生成标准访问链接 from django.urls import reverse return reverse("category_detail", kwargs={"full_slug": self.get_full_slug()}) # 新增部分结束
2. 修改路由规则,匹配多级路径
把原有单级slug的路由改为支持任意层级的path类型参数:
urlpatterns = [ # 替换原有路由,path类型可匹配带斜杠的多级路径 path('category/<path:full_slug>/', CategoryDetailView.as_view(), name='category_detail'), ]
3. 修改视图逻辑,逐层定位分类
如果是要展示单个分类的详情,推荐用DetailView更符合语义,逻辑如下:
from django.http import Http404 from django.views.generic import DetailView from .models import Category class CategoryDetailView(DetailView): model = Category template_name = 'modules/post/category_detail.html' context_object_name = 'category' def get_object(self, queryset=None): full_slug = self.kwargs["full_slug"] slug_parts = full_slug.split("/") current_parent = None # 按照路径逐层查找分类,适配parent+slug联合唯一约束 for slug in slug_parts: try: current_parent = Category.objects.get(parent=current_parent, slug=slug) except Category.DoesNotExist: raise Http404("请求的分类不存在") return current_parent
如果你的业务是要展示当前分类下的文章列表,保留ListView的话修改为:
from django.http import Http404 from django.views.generic import ListView from .models import Category, Post # 假设你的文章模型为Post,关联Category外键 class CategoryPostListView(ListView): template_name = 'modules/post/category_detail.html' context_object_name = 'posts' def get_queryset(self): full_slug = self.kwargs["full_slug"] slug_parts = full_slug.split("/") current_parent = None for slug in slug_parts: try: current_parent = Category.objects.get(parent=current_parent, slug=slug) except Category.DoesNotExist: raise Http404("请求的分类不存在") self.current_category = current_parent # 返回当前分类下的所有公开文章,可按自己的业务调整过滤条件 return Post.objects.filter(category=current_parent, is_public=True) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 把当前分类注入模板上下文 context["category"] = self.current_category return context
注意事项
- 模板中直接调用
{{ category.get_absolute_url }}即可自动生成category/一级分类/二级分类/三级分类格式的链接 - 你模型中已经配置了
parent+slug的联合唯一约束,完全匹配逐层查找的逻辑,不会出现分类冲突问题 - 如果需要兼容旧版本单级slug的链接,可以额外新增一条旧路由规则,查询到对应分类后做301跳转到新的全路径链接,避免流量损失
内容的提问来源于stack exchange,提问作者Razilator
相关产品推荐
相关产品推荐

