没有前缀的 URL

URLs with no prefixes

我想知道是否可以在没有任何额外前缀的情况下访问所有页面及其详细信息页面。

示例:

'''
/vegetables
/carrot -->  (detail page for vegetables)
/fruits
/apple  -->  (detail page for fruits)
'''

示例 URL 模式,我根据要求添加视图。

#urls.py
urlpatterns = [
    path('', views.index, name='index'),
    path('fruits/', views.all_fruits, name='fruits'),
    path('vegetables/', views.all_vegetables, name='vegetables'),
    path('<slug:slug>/', views.fruit_detail, name='fruit'),
    path('<slug:slug>/', views.vegatable_detail, name='vegetable'),
    ]

#views.py
    from .models import Fruit, Vegetable
    def index(request):
        return render (request, 'index.html')
    
    def all_fruits(request):
        fruits=Fruit.objects.all()
        return render(request, 'fruits.html', {'fruits':fruits})
    
    def all_vegetables(request):
        vegetables=Vegetable.objects.all()
        return render(request, 'vegetables.html', {'vegetables':vegetables})
    
    def fruit_detail (request, slug):
        fruit = get_object_or_404(Fruit, slug=slug)
        return render(request, 'fruit_detail.html', {'fruit':fruit})
    
    def vegetable_detail (request, slug):
        vegetable = get_object_or_404(Vegetable, slug=slug)
        return render(request, 'vegetable_detail.html', {'vegetable':vegetable})

可以预见;尝试访问蔬菜详情页面时,由于使用了水果的视图而出错。

提前感谢您的帮助和反馈。

当您首先在 Fruit 个对象中查找特定的 slug,然后在 Vegetable 个对象中查找特定的 slug 并将找到的实例添加到模板上下文中时,您可以通过编写特殊的重定向视图来实现您想要实现的目标 但是它是非常低效和“肮脏”的。使用标准 urls(就像你现在所做的那样)Django 路由器将不知道当有人输入时你指的是哪个 slug 例如 yoursite.com/xyzabc Django 不知道它是否应该查找例如插入 fruit table 或 vegetable table。

您应该像现在一样继续创建问题,但我建议您使用(在我看来)使用 Django 的更成熟的解决方案generic views. Of course you can use them without deep understanding of Class Based Views,但我强烈建议您使用它们。

简介

正如您可能注意到的那样,您对所有基于函数的视图使用了“相同的”copy/paste 代码。在一个小项目上这样做没问题但是你应该总是想让你的代码灵活、可扩展,更重要的是易于refactor/reformat

ListView

当您的大部分视图都专注于呈现像 all_fruitsall_vegetables

这样的对象列表时,

很有用

DetailView

当您想显示带有特定实例信息的模板时很有用。这正是您在 fruit_detailvegetable_detail

中所做的

你的代码是用 CBV 写的
views.py

    from .models import Fruit, Vegetable
    from django.views.generic.base import TemplateView
    from django.views.generic.detail import DetailView
    from django.views.generic.list import ListView

    class IndexView(TemplateView):
        template_name = 'index.html'
    
    # former all_fruits view
    class FruitListView(ListView):
        model = Fruit
        template_name = 'fruits.html'
  
    class VegetableListView(ListView):
        model = Vegetable
        template_name = 'vegetables.html'

    # former fruit_detail view
    class FruitDetailView(DetailView):
        model = Fruit
        template_name = 'fruit_detail.html'

    class VegetableDetailView(DetailView):
        model = Vegetable
        template_name = 'vegetable_detail.html'

如果您仔细研究通用视图,您会发现如果您根据 Django 的文档构建项目树,甚至可以跳过 template_name 部分
urls.py

urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('fruits/', views.FruitListView.as_view(), name='fruits'),
    path('vegetables/', views.VegetableListView.as_view(), name='vegetables'),
    path('fruits/<slug:slug>/', views.FruitDetailView.as_view(), name='fruit'),
    path('vegetables/<slug:slug>/', views.VegetableDetailView.as_view(), name='vegetable'),
    ]

上面的答案显示了应该如何按照最佳 Django 实践来完成,但我们知道有时客户有特殊需求,例如由于 CEO 的原因所以为了完全回答这里的问题是如何访问多个详细信息页面使用一条路线的模型 (url)。
views.py

# instead of using two views VegetableDetailView and FruitDetalView 
# we will use one common view to filter out the needed instance
# Rest of the code stays as in upper answer

...

class FruitOrVegetableDetailView(View):
    def get(self, request, slug, *args, **kwargs)
        try:
            return render(request, 'fruit_detail.html', 
                    {'fruit': Fruit.objects.get(slug=slug)})
        except Fruit.DoesNotExist:
            veg = get_object_or_404(Vegetable, slug=slug)
            return render(request, 'vegetable_detail.html', 
                    {'vegetable': veg})

当然我们需要改变路由
urls.py

urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('fruits/', views.FruitListView.as_view(), name='fruits'),
    path('vegetables/', views.VegetableListView.as_view(), name='vegetables'),
    path('<slug:slug>/', views.FruitOrVegetableDetailView.as_view(), name='fruit_or_vegetable_detail'),
    ]