【问题标题】:URLs with no prefixes不带前缀的网址
【发布时间】:2021-02-06 01:24:29
【问题描述】:

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

例子:

'''
/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})

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

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

【问题讨论】:

  • 请发表你的看法
  • @AndreyBorzenko 我添加了视图。
  • 我发布了一个相当长的答案,这并不完全是对您问题的代码答案,而是对新 Django 开发人员的建议。如果你真的对你的问题的答案是什么我不推荐我也可以发布它
  • @quqa123 您的建议和解释非常有价值,我很感激。另外,我知道显示没有前缀的详细信息页面效率低下,但我想体验一下,所以如果您也可以发布问题的答案,我会很高兴。
  • 如果您觉得答案有帮助,请点赞,以便其他人也可以将其用作有效的学习资源

标签: python django url django-urls


【解决方案1】:

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

您应该像现在一样继续创建您的问题,但我建议您使用(在我看来)更成熟的解决方案,使用 Django 的 generic views。当然你可以在没有深入了解Class Based Views的情况下使用它们,但我强烈建议你使用它们。

简介

您可能注意到,您对所有基于函数的视图都使用了“相同”的复制/粘贴代码。在一个小项目上这没什么问题但是你应该总是想让你的代码灵活、可扩展并且更重要的是易于重构/重新格式化

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'),
    ]

上面的 anwser 展示了它应该如何遵循最佳 Django 实践,但我们知道有时客户有特殊需求,例如由于 CEO 原因,所以为了完全回答这里的问题是如何使用访问多个模型的详细信息页面一条路线(网址)。
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'),
    ]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 2021-11-12
    • 1970-01-01
    • 2013-11-28
    • 2021-05-03
    • 2017-05-04
    • 2015-06-15
    相关资源
    最近更新 更多