Django 多重<;slug:slug>;根上的URL模式

Django 多重<;slug:slug>;根上的URL模式,django,django-models,django-views,Django,Django Models,Django Views,手动输入URL对于我正在工作的网站来说非常重要。几乎所有流量都来自直接访问domain.com/some string/的用户。最小的流量将来自搜索引擎 这意味着让URL像人们一样容易记住是非常重要的 有没有办法在根目录中有多个路径('/',…)URL模式 例如,我的模型: from django.db import models class Category(models.Model): class Meta: verbose_name_plural = 'categori

手动输入URL对于我正在工作的网站来说非常重要。几乎所有流量都来自直接访问
domain.com/some string/
的用户。最小的流量将来自搜索引擎

这意味着让URL像人们一样容易记住是非常重要的

有没有办法在根目录中有多个
路径('/',…)
URL模式

例如,我的模型:

from django.db import models    
class Category(models.Model):
  class Meta:
    verbose_name_plural = 'categories'
  title  = models.CharField(max_length=50)
  slug = models.SlugField(max_length=50)
  description = models.TextField()
  parent = models.ForeignKey('self', on_delete=models.PROTECT, null=True, blank=True)
  def __str__(self):
    return self.title

class Widget(models.Model):
  title = models.CharField(max_length=50)
  slug = models.SlugField(max_length=50)
  # and various other parameters specific to Widget
  category = models.ForeignKey('Category', on_delete=models.PROTECT, related_name = 'widgets', null=True)  
  def __str__(self):
    return self.title
我的看法是:

from django.views.generic import ListView, DetailView

from .models import Category, Widget
  
class WidgetDetailView(DetailView):
  model = Widget
  slug_field = 'slug'
  slug_url_kwarg = 'slug'

class CategoryListView(ListView):
  model = Category
  slug_field = 'slug'
  slug_url_kwarg = 'slug'
和我的网址:

from django.urls import path

from .views import WidgetDetailView, CategoryListView

urlpatterns = [
  path('<slug:slug>/', WidgetDetailView.as_view(), name='widget-detail')
  path('<slug:slug>/', CategoryListView.as_view(), name='category-list')
]
从django.url导入路径
从.views导入WidgetDetailView、CategoryListView
URL模式=[
路径('/',WidgetDetailView.as_view(),name='widget-detail')
路径(“/”,CategoryListView.as_view(),name='category-list')
]
但显然,这适用于
domain.com/widget slug/
,但不适用于
domain.com/category slug/
,因为只有第一个URL模式被调用,结果是404

我认为一个解决方案是在Widget和Category模型中创建一个与Slug模型的通用关系。然后,slug“view”可以使用“content\u type.model”和“content\u object.pk”返回正确的模型视图。但这似乎是一个不必要的复杂解决方案,我认为这是一个常见问题

我错过了什么明显的东西吗?当我搜索诸如“根上的多弹头模式”之类的东西时,我似乎找不到任何其他人试图实现这一点

我知道这不是构建URL的理想方式,但正如我所说的,输入流量对这个网站至关重要。使URL尽可能容易记住是非常重要的


谢谢。

是的,您必须创建一个视图,然后根据传递的slug处理分配到正确型号的操作。您不能以任何方式将同一路径模式映射到多个视图。

是的,您必须创建一个视图,然后根据传递的slug将其分派到正确的模型类型。您不能以任何方式将同一路径模式映射到多个视图。

解决方案1:调度视图

您可以创建一个
dispatch\u视图
,如下所示:

url.py

urlpatterns=[
路径(“/”,调度视图,name='dispatch')
]
views.py

从django.http导入Http404
def dispath_视图(请求、段塞):
尝试:
Category.objects.get(slug=slug)
除Category.DoesNotExist外:
尝试:
Widget.objects.get(slug=slug)
除Widget.DoesNotExist外:
升起Http404(“未找到”)
其他:
返回WidgetDetailView.as_view()(请求,slug)
其他:
返回CategoryListView.as_view()(请求,slug)
解决方案2:调度模型

更深入地说,您可以创建一个
Dispatch
模型来存储模型的每个slug(在
save()
delete()
上),如下所示(未测试),以防止
小部件
类别
之间的slug重复:

类调度(models.Model):
类视图选项(models.TextChoices):
类别='CAT','myapp.views.CategoryListView'
WIDGET='WDT','myapp.views.WidgetDetailView'
视图=models.CharField(
最大长度=3,
choices=ViewChoices.choices,
默认值=ViewChoices.CATEGORY,
)
slug=型号。SlugField(最大长度=50,唯一性=真)
以及相关视图:

来自django.utils.module\u加载导入\u字符串
def dispath_视图(请求、段塞):
尝试:
dispatch\u obj=dispatch.objects.get(slug=slug)
除Dispatch.DoesNotExist外:
提高Http404()
其他:
视图=导入字符串(dispatch\u obj.get\u view\u display()).as\u view()
返回视图(请求、段塞)
解决方案3:使用模型继承

另一种方法是使用模型继承来防止
小部件
类别
::


class BaseSlug(models.Model):
    slug = models.SlugField(max_length=50, unique=True)

class Widget(BaseSlug):
    ...

class Category(BaseSlug):
    ...

并使用解决方案1中的视图

解决方案1:调度视图

您可以创建一个
dispatch\u视图
,如下所示:

url.py

urlpatterns=[
路径(“/”,调度视图,name='dispatch')
]
views.py

从django.http导入Http404
def dispath_视图(请求、段塞):
尝试:
Category.objects.get(slug=slug)
除Category.DoesNotExist外:
尝试:
Widget.objects.get(slug=slug)
除Widget.DoesNotExist外:
升起Http404(“未找到”)
其他:
返回WidgetDetailView.as_view()(请求,slug)
其他:
返回CategoryListView.as_view()(请求,slug)
解决方案2:调度模型

更深入地说,您可以创建一个
Dispatch
模型来存储模型的每个slug(在
save()
delete()
上),如下所示(未测试),以防止
小部件
类别
之间的slug重复:

类调度(models.Model):
类视图选项(models.TextChoices):
类别='CAT','myapp.views.CategoryListView'
WIDGET='WDT','myapp.views.WidgetDetailView'
视图=models.CharField(
最大长度=3,
choices=ViewChoices.choices,
默认值=ViewChoices.CATEGORY,
)
slug=型号。SlugField(最大长度=50,唯一性=真)
以及相关视图:

来自django.utils.module\u加载导入\u字符串
def dispath_视图(请求、段塞):
尝试:
dispatch\u obj=dispatch.objects.get(slug=slug)
除Dispatch.DoesNotExist外:
提高Http404()
其他:
视图=导入字符串(dispatch\u obj.get\u view\u display()).as\u view()
返回视图(请求、段塞)
解决方案3:使用模型继承

另一种方法是使用模型继承来防止
小部件
类别
::


class BaseSlug(models.Model):
    slug = models.SlugField(max_length=50, unique=True)

class Widget(BaseSlug):
    ...

class Category(BaseSlug):
    ...
并使用来自solut的视图