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

基于Django/DRF实现StackOverflow式URL重定向功能

实现类似StackOverflow的URL自动重定向功能(Django/Django REST Framework)

需求说明

要实现像StackOverflow那样的URL重定向机制:只要请求中的文章pk正确,不管传入的slug是否正确(甚至不带slug),系统都会自动跳转到包含正确slug的标准URL。例如:

  • 访问http://127.0.0.1:8000/article/1/ 或 http://127.0.0.1:8000/article/1/wrong-slug/,都会自动重定向到http://127.0.0.1:8000/article/1/correct-slug/

现有代码

models.py(原代码中误写为views.py)

from django.db import models
from django.utils.text import slugify  # 原代码漏导入slugify

class ArticleBody(models.Model): 
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField()

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.title)
        return super().save(*args, **kwargs)

serializers.py

from rest_framework import serializers

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ArticleBody
        read_only_fields = (
            "id",
            "title",  # 原代码漏写逗号
            "slug"
        )
        fields = read_only_fields

views.py

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from .models import ArticleBody
from .serializers import ArticleSerializer

class ArticleView(APIView):
    def get(self, request, pk, slug=None):
        article_obj =  ArticleBody.objects.filter(id=pk).last()
        article = ArticleSerializer(article_obj).data

        if article:
            return Response({"article": article})

        return Response(
            {"message": "Article not found"}, status=status.HTTP_404_NOT_FOUND
        )

urls.py

from django.urls import path, re_path

from .views import ArticleView

app_name = "article"

urlpatterns = [ 
    re_path(r"^(?P<pk>\d+)/$", ArticleView.as_view(), name="body"),
    re_path(
        r"^(?P<pk>\d+)/(?P<slug>[-\w]+)/$", ArticleView.as_view(), name="body-slug"
    ),
]

修改方案

步骤1:给模型添加标准URL生成方法

在ArticleBody模型中添加get_absolute_url方法,用于生成正确的带slug的URL:

from django.db import models
from django.utils.text import slugify
from django.urls import reverse

class ArticleBody(models.Model): 
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField()

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.title)
        # 可选:如果标题更新,同步更新slug
        # else:
        #     self.slug = slugify(self.title)
        return super().save(*args, **kwargs)
    
    def get_absolute_url(self):
        return reverse("article:body-slug", kwargs={"pk": self.pk, "slug": self.slug})

步骤2:修改视图逻辑实现重定向

在ArticleView的get方法中,判断当前请求的slug是否与文章的正确slug一致,不一致则返回301永久重定向;如果是不带slug的请求,同样重定向到标准URL:

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from django.shortcuts import get_object_or_404, redirect
from .models import ArticleBody
from .serializers import ArticleSerializer

class ArticleView(APIView):
    def get(self, request, pk, slug=None):
        article_obj = get_object_or_404(ArticleBody, id=pk)
        
        # 检查slug是否正确,或是否传入slug
        if slug != article_obj.slug:
            # 301永久重定向,对SEO更友好
            return redirect(article_obj.get_absolute_url(), permanent=True)
        
        article = ArticleSerializer(article_obj).data
        return Response({"article": article})

步骤3:优化URL配置(可选)

用path替代re_path,写法更简洁:

from django.urls import path

from .views import ArticleView

app_name = "article"

urlpatterns = [ 
    path("<int:pk>/", ArticleView.as_view(), name="body"),
    path("<int:pk>/<slug:slug>/", ArticleView.as_view(), name="body-slug"),
]

测试验证

  • 访问http://127.0.0.1:8000/article/1/ → 自动重定向到带正确slug的标准URL
  • 访问http://127.0.0.1:8000/article/1/wrong-slug/ → 自动重定向到标准URL
  • 访问不存在的pk → 返回404错误

内容的提问来源于stack exchange,提问作者Julkar9

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:44:49