Django站点修改slug后旧URL自动重定向解决方案
Django站点Slug修改后的自动重定向方案
当你修改站点内容的slug导致旧URL失效时,不用逐个编写重定向规则,下面是两种自动处理的实用方案:
方案一:模型存储历史Slug+视图自动匹配重定向
这种方案适合单个或少数模型的场景,核心思路是把每个内容的旧slug都存在模型里,访问时自动匹配并跳转。
- 修改模型,添加历史slug字段
给需要处理的模型(比如文章、产品模型)新增一个字段保存所有用过的旧slug,推荐用JSON数组存储:
from django.db import models from django.contrib.postgres.fields import JSONField # PostgreSQL用户直接用,其他数据库可换TextField存JSON字符串 class Article(models.Model): title = models.CharField(max_length=200) slug = models.SlugField(unique=True) old_slugs = JSONField(default=list) # 存储历史slug列表 # 其他业务字段...
- 用信号自动记录旧slug
添加pre_save信号,当slug被修改时,自动把旧slug追加到历史列表:
from django.db.models.signals import pre_save from django.dispatch import receiver @receiver(pre_save, sender=Article) def track_old_slugs(sender, instance, **kwargs): if instance.pk: original = sender.objects.get(pk=instance.pk) if original.slug != instance.slug and original.slug not in instance.old_slugs: instance.old_slugs.append(original.slug)
- 修改视图,处理旧slug跳转
在详情视图里,先尝试用当前slug查找内容,找不到则匹配历史slug,找到后返回301永久重定向:
from django.shortcuts import get_object_or_404, redirect from django.views.generic import DetailView class ArticleDetailView(DetailView): model = Article slug_field = 'slug' slug_url_kwarg = 'slug' def get_object(self, queryset=None): try: return super().get_object(queryset) except self.model.DoesNotExist: # 尝试匹配旧slug target_obj = get_object_or_404(self.model, old_slugs__contains=self.kwargs['slug']) # 301重定向告诉搜索引擎更新索引 return redirect(target_obj.get_absolute_url(), permanent=True)
方案二:全局中间件处理所有404中的旧Slug
如果多个模型都有slug修改需求,可以写一个全局中间件,自动拦截404请求并尝试匹配旧slug:
- 编写中间件
在你的app下创建middleware.py文件:
from django.http import HttpResponsePermanentRedirect from django.urls import resolve class OldSlugRedirectMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # 只处理404状态的请求 if response.status_code == 404: try: match = resolve(request.path_info) # 针对需要处理的视图(替换成你的详情页视图名称) if match.view_name in ['article_detail', 'product_detail']: slug = match.kwargs.get('slug') if slug: # 根据视图名称对应不同模型 if match.view_name == 'article_detail': from .models import Article obj = Article.objects.get(old_slugs__contains=slug) elif match.view_name == 'product_detail': from .models import Product obj = Product.objects.get(old_slugs__contains=slug) return HttpResponsePermanentRedirect(obj.get_absolute_url()) except (resolve.Resolver404, Exception): # 匹配失败,返回原404 pass return response
- 注册中间件
在项目settings.py的MIDDLEWARE列表中添加该中间件:
MIDDLEWARE = [ # 其他中间件... 'your_app_name.middleware.OldSlugRedirectMiddleware', ]
关键注意点
- 必须使用301永久重定向,这样搜索引擎会更新索引,逐步替换旧URL,避免后续用户通过搜索进入错误页面。
- 若使用MySQL,可将
JSONField换成TextField,存储时转成JSON字符串,查询时用old_slugs__contains=f'"{slug}"'实现精确匹配,避免误匹配。 - 已被谷歌收录的旧URL,通过这种方式会自动跳转,无需手动维护大量重定向规则。
内容的提问来源于stack exchange,提问作者PolarBear
相关产品推荐
相关产品推荐

