首页 > 解决方案 > 自定义 Django SlugField 验证会破坏 URL 匹配

问题描述

我为 URL 中的 slug 编写了一个自定义字段验证器(接受一个模型的 slug 中的句点,SLUG_REGEX = '[-a-zA-Z0-9_.]+$'):

def validate_my_slug(value):

    my_slug_re = re.compile(settings.SLUG_REGEX)

    if not my_slug_re.match(value):
        raise ValidationError(
            _('Slugs must consist of letters, numbers, '
              'underscores, hyphens, or periods.'),
            params={'value': value},
        )

中的字段models.py

slug = models.CharField(max_length=64, null=True, blank=True, 
                        validators=[validate_my_slug])

这在 Django admin 中保存模型时有效。但是在我的 URLConf 中,这不再有效(它在更改 slug 验证之前确实有效):

path('product-release/<slug:slug>', ProductReleaseDetail.as_view(), 
     name='product-detail')
  1. 我找到了一个解决方案re_path,但我不确定这是正确/最好的方法:

     re_path('product-release/(?P<slug>[-a-zA-Z0-9_.]+)$', 
             ProductReleaseDetail.as_view(), 
             name='product-release-detail')
    
  2. 现在这不再有效(出现在re_path上面的模式之前urls.py):

     path('product-releases', ProductReleaseList.as_view(), 
          name='product-release-list')
    

除了与产品发布列表匹配的内容外,一切正常。当我更改 slug 验证器时,URLhttp://localhost:8080/product-releases停止工作,并出现错误:

NoReverseMatch at /product-releases
Reverse for 'product-release-detail' with no arguments not found.
1 pattern(s) tried: ['product-release/(?P<slug>[-a-zA-Z0-9_.]+$)']

但这似乎是错误的,因为我什至没有尝试达到product-release-detail;我试图达到product-release-list。我一定在这里遗漏了一些简单的东西,但现在我的视野变得模糊了。

views.py

. . .

class ProductReleaseList(ListView):
    model = ProductRelease


class ProductReleaseDetail(DetailView):
    model = ProductRelease

. . .

urlpatterns

. . .

# Product Releases
path('product-releases', ProductReleaseList.as_view(), name='product-release-list'),
re_path('product-release/(?P<slug>[-a-zA-Z0-9_.]+$)', ProductReleaseDetail.as_view(), name='product-release-detail'),
# Release Notes
path('release-notes', ReleaseNoteList.as_view(), name='release-note-list'),
re_path('release-note/(?P<slug>[-a-zA-Z0-9_.]+$)', ReleaseNoteDetail.as_view(), name='release-note-detail'),

. . .

productrelease_list.html

. . .

<h4><a href="{% url 'product-release-detail' %}">{{ p }}</a></h4>

. . .

标签: djangovalidationdjango-urlsslug

解决方案


在您的模板中,您使用的是类似于:

{% url "product-release-detail" varname %}

然而,这个变量显然可以是空的(或者由于拼写错误甚至总是空的)。这样就完成了/<slug:slug>(我不同意顺便说一句,但这不是重点)。随着您的限制和更好re_path,现在(正确地)会产生一个错误,因为/product-release/它不是一个有效的 url:一个 slug 应该至少有一个字符。

所以根本原因是以太,变量命名不正确,或者你有没有蛞蝓的产品(你不应该有)。

地址评论

  1. 在模板中注释掉是用{# #}. 确保您没有使用<!-- -->,因为它仍然执行代码。
  2. 就目前而言{% url "product-release-detail" %}是无效的:它需要一个论据,即一个蛞蝓。如果要链接到列表视图,请使用{% url "product-release-list" %}as 可以不带参数调用。
  3. 我不知道 {{ p }} 是什么,但我假设是产品对象。在这种情况下,您应该使用{%url "product-release-detail" p.name_of_slug_field %}.

推荐阅读