Django表单提交后如何修改视图URL去除用户名后缀?
问题描述
在Django开发的博客项目中,单篇文章详情页URL为http://127.0.0.1:8002/articles/article/aviary-ensemble/(aviary-ensemble为文章slug),页面内置评论提交表单。当前details视图同时处理页面加载与评论创建逻辑,URL配置包含两条路径:一条带<str:author>参数,一条不带。提交评论后,URL自动变为带用户名后缀的地址(如http://127.0.0.1:8002/articles/article/aviary-ensemble/admin/),期望提交后回到无后缀的原详情页地址。尝试修改request.path_info未生效,寻求可行实现方案。
相关代码如下:
视图代码
def details(request, slug, author=None): article = models.Article.objects.get(slug=slug) print(author) if request.method == 'POST': if author is not None: user = User.objects.get(username=author) print(user.username, type(user)) comment_author = UserProfile.objects.get(user=user) comment = request.POST['comment_area'] if comment[0] == '@': receiver = comment[1:].split(', ')[0] comment_text = comment[1:].split(', ')[1] models.Comment.objects.create(article=article, author=comment_author, receiver=receiver, text=comment_text) else: models.Comment.objects.create(article=article, author=comment_author, text=comment) article_comments = models.Comment.objects.filter(article=article) context = {'article': article, 'article_comments': article_comments} return render(request, 'articles/article.html', context=context) else: article.views = article.views + 1 article_comments = models.Comment.objects.filter(article=article) context = {'article': article, 'article_comments': article_comments} return render(request, 'articles/article.html', context=context)
URL配置
urlpatterns = [ path('', views.index, name='articles_catalog'), path('article/<slug:slug>/<str:author>/', views.details, name='comment_creation'), path('article/<slug:slug>/', views.details, name='details'), ]
解决方案
核心问题分析
提交后URL带author后缀的原因是:表单提交到了带<str:author>参数的comment_creation路由,且处理完POST请求后直接用render返回页面,浏览器会保留当前请求的URL。修改request.path_info仅改变Django内部请求路径,不会触发浏览器地址栏更新。
方案一:POST处理后重定向到无author的详情页(快速修复)
遵循POST/REDIRECT/GET模式,处理完评论创建后,用redirect跳转到不带author参数的details路由,强制浏览器更新地址栏。
修改视图的POST分支代码:
if request.method == 'POST': if author is not None: # 保留原评论创建逻辑 user = User.objects.get(username=author) comment_author = UserProfile.objects.get(user=user) comment = request.POST['comment_area'] if comment[0] == '@': receiver = comment[1:].split(', ')[0] comment_text = comment[1:].split(', ')[1] models.Comment.objects.create(article=article, author=comment_author, receiver=receiver, text=comment_text) else: models.Comment.objects.create(article=article, author=comment_author, text=comment) # 替换原render语句,重定向到无author的详情页 return redirect('details', slug=slug)
方案二:调整表单提交目标(避免依赖重定向)
直接修改模板中的评论表单,让它提交到不带author参数的details路由,同时通过隐藏字段传递author信息(如果需要)。
- 模板中修改表单提交地址:
<form method="post" action="{% url 'details' slug=article.slug %}"> {% csrf_token %} <!-- 隐藏传递author参数 --> <input type="hidden" name="author" value="{{ request.user.username }}"> <textarea name="comment_area"></textarea> <button type="submit">提交评论</button> </form>
- 视图中从POST参数获取author,移除URL的author参数:
def details(request, slug): article = models.Article.objects.get(slug=slug) if request.method == 'POST': author_username = request.POST.get('author') if author_username: user = User.objects.get(username=author_username) comment_author = UserProfile.objects.get(user=user) comment = request.POST['comment_area'] if comment[0] == '@': receiver = comment[1:].split(', ')[0] comment_text = comment[1:].split(', ')[1] models.Comment.objects.create(article=article, author=comment_author, receiver=receiver, text=comment_text) else: models.Comment.objects.create(article=article, author=comment_author, text=comment) return redirect('details', slug=slug) else: article.views += 1 article.save() # 原代码遗漏保存浏览量修改,需补充 article_comments = models.Comment.objects.filter(article=article) context = {'article': article, 'article_comments': article_comments} return render(request, 'articles/article.html', context=context)
方案三:移除带author的URL路由(最佳实践)
无需通过URL传递用户信息,直接用request.user获取当前登录用户,简化路由配置,彻底避免URL混乱。
修改后的URL配置:
urlpatterns = [ path('', views.index, name='articles_catalog'), path('article/<slug:slug>/', views.details, name='details'), ]
修改后的视图代码:
def details(request, slug): article = models.Article.objects.get(slug=slug) if request.method == 'POST': # 直接从当前登录用户获取信息(需确保用户已登录) if request.user.is_authenticated: comment_author = UserProfile.objects.get(user=request.user) comment = request.POST['comment_area'] if comment[0] == '@': receiver = comment[1:].split(', ')[0] comment_text = comment[1:].split(', ')[1] models.Comment.objects.create(article=article, author=comment_author, receiver=receiver, text=comment_text) else: models.Comment.objects.create(article=article, author=comment_author, text=comment) return redirect('details', slug=slug) else: article.views += 1 article.save() article_comments = models.Comment.objects.filter(article=article) context = {'article': article, 'article_comments': article_comments} return render(request, 'articles/article.html', context=context)
内容的提问来源于stack exchange,提问作者Ксения Манжула

