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

Django添加菜单项时URL出现双斜杠//引发404错误求助

Django URL双斜杠导致404错误的修复方案

问题描述

在Django项目中添加新菜单项时,生成的URL出现双斜杠//,触发404页面未找到错误。请求URL为http://127.0.0.1:8000/restaurant/menu/desserts-menu//add_menuItem/,无法匹配项目中已定义的URLconf规则。

项目相关代码

Urls.py

from django.urls import path
from restaurant import views
app_name = 'restaurant'

urlpatterns = [
    path('', views.index, name='index'),
    path('about/', views.about, name = 'about'),
    path('menu/<slug:menu_name_slug>/add_menu_item/', views.add_menu_item, name='add_menu_item'),
    path('menu/<slug:menu_name_slug>/', views.show_menu, name='show_menu'),
    path('menu/<slug:menu_name_slug>/<slug:menuItem_name_slug>/', views.show_menu_item, name='show_menu_item'),
    #Template shows form but without any functionality
    path('add_menu/', views.add_menu, name="add_menu"),
    path('menu/<slug:menu_name_slug>/<slug:menuItem_name_slug>/add_review/', views.add_review, name="add_review"),
    path('restricted/', views.restricted, name='restricted'),
]

Views.py

def show_menu(request,menu_name_slug):
    context_dict = {}
    try:
        menu = Menu.objects.get(slug=menu_name_slug)
        menuItems = MenuItem.objects.filter(menu=menu)
        context_dict['menuItems'] = menuItems
        context_dict['menu'] = menu
    except Menu.DoesNotExist:
        context_dict['menu'] = None
        context_dict['menuItems'] = None

    return render(request, 'restaurant/menu.html', context=context_dict)

def show_menu_item(request, menu_name_slug, menuItem_name_slug):
    context_dict = {}
    
    try:
        menu = Menu.objects.get(slug=menu_name_slug)
        menuItem = MenuItem.objects.get(slug=menuItem_name_slug)
        reviews = Review.objects.filter(menuItem=menuItem)
        context_dict['reviews'] = reviews
        context_dict['menuItem'] = menuItem
        context_dict['menu'] = menu
    except Menu.DoesNotExist:
        context_dict['menu'] = None
        context_dict['menuItem'] = None
        context_dict['reviews'] = None

    return render(request, 'restaurant/menu_item.html', context=context_dict)

@login_required
def add_menu_item(request, menu_name_slug):
    try:
        menu = Menu.objects.get(slug=menu_name_slug)
    except Menu.DoesNotExist:
        menu = None
    if menu is None:
        return redirect('/restaurant/')
    form = MenuItemForm()
    if request.method == 'POST':
        form = MenuItemForm(request.POST)
        if form.is_valid():
            if menu:
                menuItem = form.save(commit=False)
                menuItem.menu = menu
                menuItem.save()
                return redirect(reverse('restaurant:show_menu', kwargs={'menu_name_slug': menu_name_slug}))
        else:
            print(form.errors)

    context_dict = {'form': form, 'menu': menu}
    return render(request, 'restaurant/add_menuItem.html', context=context_dict)

@login_required
def add_review(request, menu_name_slug, menuItem_name_slug):
    try:
        menuItem = MenuItem.objects.get(slug=menuItem_name_slug)
    except MenuItem.DoesNotExist:
        menuItem = None
    if menuItem is None:
        return redirect('/restaurant/')
    form = ReviewForm()
    if request.method == 'POST':
        form = ReviewForm(request.POST)
        if form.is_valid():
            if menuItem:
                review = form.save(commit=False)
                review.menuItem = menuItem
                review.save()
                return redirect(reverse('restaurant:show_menu_item', kwargs={'menuItem_name_slug': menuItem_name_slug}))
        else:
            print(form.errors)

    context_dict = {'form': form, 'menuItem': menuItem}
    return render(request, 'restaurant/add_review.html', context=context_dict)

Models.py

class Menu(models.Model):
    MENU_ID_MAX_LENGTH=128
    menuID = models.TextField(max_length=MENU_ID_MAX_LENGTH,unique=True) # primary key
    slug = models.SlugField(unique=True)
    def save(self, *args, **kwards):
        self.slug = slugify(self.menuID)
        super(Menu, self).save(*args, **kwards)
    def __str__(self):
        return self.menuID
    
class MenuItem(models.Model):
    MENUITEM_ID_MAX_LENGTH=128
    DESCRIPTION_MAX_LENGTH=200
    menuItemID = models.CharField(max_length=MENUITEM_ID_MAX_LENGTH, unique=True) # primary key 
    menu = models.ForeignKey(Menu, on_delete=models.CASCADE) # foreign key: one to many - many menu items for one menu
    description = models.CharField(max_length=DESCRIPTION_MAX_LENGTH, default="None")
    price = models.FloatField(default =0.0)
    photo = models.ImageField(upload_to='menu_item_images', blank=True)
    slug = models.SlugField(unique=True)
    def save(self, *args, **kwards):
        self.slug = slugify(self.menuItemID)
        super(MenuItem, self).save(*args, **kwards)
    class Meta:
        verbose_name_plural = 'MenuItems'
    def __str__(self):
        return self.menuItemID
    
class Review(models.Model):
    REVIEW_ID_MAX_LENGTH=128
    COMMENT_MAX_LENGTH=1000
    reviewID =  models.CharField(max_length=REVIEW_ID_MAX_LENGTH, unique=True) # primary key 
    user = models.ForeignKey(User, on_delete=models.CASCADE) # foreign key: one to many - many reviews for one user 
    menuItem = models.ForeignKey(MenuItem, on_delete=models.CASCADE) # foreign key: one to many - many reviews for one menu item
    comment = models.CharField(max_length=COMMENT_MAX_LENGTH)
    ratings = models.IntegerField(default =0)
    photo = models.ImageField(upload_to='review_images', blank=True)
    def __str__(self):
        return self.reviewID

问题分析与修复

核心问题

  1. 大小写不匹配:请求URL中的add_menuItem/(大写I)与URLconf定义的add_menu_item/(下划线+小写i)不一致,Django URL匹配大小写敏感,直接导致路径无法匹配。
  2. 双斜杠来源:手动拼接URL时,前半路径末尾带斜杠,后半路径开头又带斜杠,比如模板中写{{ menu.get_absolute_url }}/add_menuItem/,而get_absolute_url返回的路径本身带末尾斜杠,拼接后出现双斜杠。

修复步骤

1. 用Django官方方式生成URL(彻底避免双斜杠和拼写错误)

放弃手动拼接URL,改用url模板标签或reverse函数生成,确保路径完全匹配URLconf:

  • 模板中使用url标签:
<a href="{% url 'restaurant:add_menu_item' menu_name_slug=menu.slug %}">添加菜单项</a>
  • 视图中使用reverse函数:
from django.urls import reverse
# 生成添加菜单项的URL示例
url = reverse('restaurant:add_menu_item', kwargs={'menu_name_slug': menu.slug})

2. 修正路径大小写

如果之前手动写了URL路径,将add_menuItem改为add_menu_item,与URLconf中的定义保持一致。

3. 可选:为Menu模型添加规范的URL生成方法

在Menu模型中添加get_absolute_url,统一菜单详情页的URL生成:

class Menu(models.Model):
    # ... 现有代码 ...
    def get_absolute_url(self):
        return reverse('restaurant:show_menu', kwargs={'menu_name_slug': self.slug})

验证修复

修改后生成的正确URL应为http://127.0.0.1:8000/restaurant/menu/desserts-menu/add_menu_item/,无斜杠重复且路径匹配,可正常访问添加菜单项页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:13:11