You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:18:02