强制 url 中的两个 slug 都存在于数据库中

Posted

技术标签:

【中文标题】强制 url 中的两个 slug 都存在于数据库中【英文标题】:force both slugs in url to exist in datatabse 【发布时间】:2019-03-24 09:36:47 【问题描述】:

我有多个类别以及通过 ForeignKey 与这些类别相关的一些详细信息。

例如,我有 categorie1 和 detail1。

现在我可以在 url localhost:8000/categorie1 中调用类别

 path('<slug>', views.CategorieView.as_view(), name='categorie_name')

和详细信息:localhost:8000/categorie1/detail1

path('<anythinghereworks>/<slug>', views.DetailView.as_view(), name='detail_name')

但正如第一个 slug 中所写,任何像 localhost:8000/abc/details1 这样的 URL 都可以使用。

如何制作特定于 2 条蛞蝓的图案?

#Model

class Categorie(models.Model):
name = models.CharField(max_length=50,unique=True)
slug = models.SlugField(max_length=100,unique=True)

def __str__(self):
    return self.name

class Detail(models.Model):
    title = models.CharField(max_length=100)
    slug= models.SlugField(max_length=100,unique=True)
    categorie = models.ForeignKey('Categorie', on_delete=models.CASCADE,  related_name="details")


    def __str__(self):
        return self.title 

#Views

class CategorieView(DetailView):
    model = Categorie
    slug_field = 'slug'
    template_name = "app/categories.html"

class DetailView(DetailView):
    model = Detail
    slug_field = 'slug'
    template_name = "app/details.html"

#URLs

path('<slug>', views.CategorieView.as_view(), name='categorie_name'),
path('<anythinghereworks>/<slug>', views.DetailView.as_view(), name='detail_name'),

【问题讨论】:

【参考方案1】:

首先,将'anythinghereworks' 重命名为更有用的名称,并重命名DetailView 以避免与Django 的DetailView 发生冲突。例如:

path('<cat_slug>/<slug>', views.MyDetailView.as_view(), name='detail_name')

然后您可以覆盖get_object 以过滤slugcat_slug

class MyDetailView(DetailView):
    def get_object(self):
        return Detail.objects.get(slug=self.kwargs['slug'], categorie__slug='self.kwargs['cat_slug'])

或者您可以覆盖get_queryset 并在那里过滤类别。你不需要在这里过滤slug=self.kwargs['slug'],因为Django会在get_object方法中处理它。

class MyDetailView(DetailView):
    def get_queryset(self):
        queryset = super().get_queryset()
        queryset = queryset.filter(categorie__slug=self.kwargs['cat_slug'])
        return queryset

您可以在这两种情况下删除slug_field = 'slug',因为'slug' 是默认值。在第一种情况下,Django 将使用您的 get_object 方法,因此根本不会使用 slug_field

【讨论】:

【参考方案2】:

你使用slug: path converter [Django-doc]:

path('<slug:slug>', views.CategorieView.as_view(), name='categorie_name'),
path(
    '<slug:anythinghereworks>/<slug:slug>',
    views.DetailDetailView.as_view(),
    name='detail_name'
),

路径转换器封装指定可接受模式的正则表达式(例如,int: 路径转换器将仅匹配数字序列),以及 URL 中的子字符串和对象之间的转换。这可以是一个字符串,例如在 slug 的情况下,但 int: 路径转换器以 int 为目标。

然后在您的Views 中,您可以覆盖get_queryset 方法:

class DetailDetailView(DetailView):
    model = Detail
    slug_field = 'slug'
    template_name = "app/details.html"

    def get_queryset(self):
        return super(DetailView, self).get_queryset().filter(
            category__slug=self.request.kwargs['anythinghereworks']
        )

正确过滤查询集。对于带有无效 sluganythinghereworks 的请求,这将引发 404。

(强烈)建议不要将任何东西命名为DetailView,因为它会覆盖模块中对新构造类的引用,因此其他文件后面的视图,将继承自你的 DetailView

不过,我建议寻找比anythinghereworks 更好的命名法。例如,您可以将参数重命名为 category_slugdetail_slug。这将避免很多混乱和(潜在的)错误。

【讨论】:

thx 但我的问题更多是我应该如何编写我的 detailView 以便只有真正存在的类别才会给出响应。因为现在我仍然可以将任何东西写成 slug:anythinghereworks in path('/' 这将给出答案。 @Alasdair:我知道,但我个人觉得这个“糟糕的设计”:) 很多 Python 包都有这样“神奇的名字”,就像俗话说的那样:“在一个好的编程语言中,只有三个常数 0、1 和无穷大”,它在某种程度上也适用于字符串。此外,视图名称DetailView,或者实际上SIngleObjectMixin 并没有暗示它应用了某些过滤器,这不是很“优雅”恕我直言。

以上是关于强制 url 中的两个 slug 都存在于数据库中的主要内容,如果未能解决你的问题,请参考以下文章

url中的wordpress自定义帖子类型类别slug

角度 5 中具有相同 URL 的两个不同组件(通过延迟加载在路由器中传递 slug)

Django:两个模型中的一个 url 搜索(cbv)

Ember 使用无效的 URL Slug 渲染 404

在 Oracle 中制作唯一的 slug url

Laravel Route 模型绑定(slug)仅适用于 show 方法?