基于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
相关产品推荐
相关产品推荐

