Django Urls - 具有相同正则表达式的两个视图

Posted

技术标签:

【中文标题】Django Urls - 具有相同正则表达式的两个视图【英文标题】:Django Urls - two views with same regular expression 【发布时间】:2018-03-01 23:35:01 【问题描述】:

我有两个具有相同正则表达式的视图,如下所示。这是一个 Category 和一个 Article 视图,它们的条目 slug 永远不会相同,所以应该没问题。但目前它不能很好地工作,因为你知道类别视图会被触发。

请不要建议使 url 结构独特,类别和文章的 slug 永远不会相同。它应该尽可能短。

urls.py

urlpatterns = [
    url(r'^index', index.Index.as_view(), name='index'),
    url(r'^search', search.Index.as_view(), name='search'),
    url(r'^(?P<slug>.+)$', category.Index.as_view(), name='category'),
    url(r'^(?P<slug>.+)$', article.Index.as_view(), name='article'),
]

如果找不到这样的类别,我尝试从 views.category 反转回 urls.py:

views.category.py

class Index(View):
    def get(self, request, slug):
        category = CategoryModel.objects.get(slug=slug)
        if category is None:
            return HttpResponseRedirect(reverse('article', args=[slug]))

        context = 
            'category': category
        
        return render(request, 'category/index.html', context)

错误(但有一篇文章带有 slug 'test123'):

NoReverseMatch at /wiki/test123
Reverse for 'article' with arguments '('test123',)' and keyword arguments '' not found. 0 pattern(s) tried: []

使用 Python 3.6

【问题讨论】:

如果您不这样做,而是使您的 URL 明确,您将有一个更轻松的时间。 这完全不是我想要的,但还是谢谢。 我想你可能不明白你要求路由器做什么。仅凭文字如何区分类别和文章? 【参考方案1】:

你为什么不尝试像这样区分网址

urlpatterns = [
    url(r'^index', index.Index.as_view(), name='index'),
    url(r'^search', search.Index.as_view(), name='search'),
    url(r'^category/(?P<slug>.+)$', category.Index.as_view(), name='category'),
    url(r'^article/(?P<slug>.+)$', article.Index.as_view(), name='article'),
]

您可以使用相同的正则表达式而不会使 URL 不明确。

【讨论】:

【参考方案2】:

您可以删除article.Index 视图,而不是在没有Category 的对象时尝试重定向,您可以调用您在article.Index 中定义的方法,其参数与get 方法在@ 中的参数相同987654325@查看。

示例

urls.py

urlpatterns = [
  url(r'^index', index.Index.as_view(), name='index'),
  url(r'^search', search.Index.as_view(), name='search'),
  url(r'^(?P<slug>.+)$', category.Index.as_view(), name='category'),
  # article url removed
]

views.category.py

from path.to.article import Index as ArticleIndexView

class Index(View):
    def get(self, request, slug):
        category = CategoryModel.objects.get(slug=slug)
        if category is None:
            # calling article app's Index get method
            article_index_view_obj = ArticleIndexView()
            return article_index_view_obj.get(request, slug)

        context = 
            'category': category
        
        return render(request, 'category/index.html', context)

如果您将article.Index 类视图设为基于函数的视图。 你可以导入from path.to.article import index as article_index 然后,您可以直接调用article_index(request, slug),而不是实例化对象。

【讨论】:

谢谢。这就是我发现的,但我认为可以使用两个不同的视图文件来解决这个问题。 是的,然后您可以实例化article.Index 视图并在创建的实例上调用get 方法或使用基于函数的视图,这比基于类的视图更容易。 是的对不起我想我不明白 不起作用。我猜是因为它是一个 as_view() 类【参考方案3】:

这里有几个问题。

(1) 您使用args 调用reverse,但您指定了kwarg

if category is None:
    return HttpResponseRedirect(reverse('article', args=[slug]))

找不到带有参数“('test123',)”和关键字参数“”的“文章”。

确切地说 - 因为您没有提供关键字参数,所以它找不到匹配的 URL 模式。这是正确的:

if category is None:
    return HttpResponseRedirect(reverse('article', kwargs='slug':slug))

(2) 您将一次又一次地使用相同的代码 - 这是我希望在您修复 (1) 后发生的情况。因为如果 reverse 确实反转了 URL - reverse 的结果当然也会匹配 category URL,这意味着它会再次调用 category.Index 视图。

我认为您的 URL 设置实际上可以工作,因为解析器确实会按顺序尝试所有 URL,直到出现匹配的 URL。我只是不确定您是否可以让视图返回导致 URL 解析器启动并决定采用下一个 URL (article) 而不是刚刚解析的 category 的内容。应该不会吧。

在这种情况下,如果您可以使用重定向,您可以定义 3 个 URL 模式。 1 表示将作为开关操作并分别重定向到 CategoryView 或 ArticleView 的视图。

否则,请使用 Sachin Kukreja 的解决方案,在一个视图中处理这两个问题。

【讨论】:

【参考方案4】:

最后我做到了。实际上我想使用 2 个不同的视图,但我想这也很好。有人看错了吗?

class Index(View):
    def get(self, request, slug):
        self.request = request
        self.slug = slug
        self.item = None
        is_article = ArticleModel.objects.filter(slug=self.slug).exists()

        if is_article:
            self.item = 'article'
            return self.article()

        is_category = CategoryModel.objects.filter(slug=self.slug).exists()
        if is_category:
            self.item = 'category'
            return self.category()

        self.item = None
        # 404 here
        return HttpResponse(self.item)

    def article(self):
        article = ArticleModel.objects.get(slug=self.slug)
        context = 
            'article': article
        
        return render(self.request, 'article/index.html', context)

    def category(self):
        category = CategoryModel.objects.get(slug=self.slug)
        context = 
            'category': category
        
        return render(self.request, 'article/index.html', context)

【讨论】:

以上是关于Django Urls - 具有相同正则表达式的两个视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的 Django urls.py 中使用单个正则表达式捕获多个参数?

匹配另一个 url - 正则表达式 django urls

Django视图层之路由配置系统(urls)

Django url 正则表达式命中 url: *./something

Django中关于URL配置文件urls.py的理解

Django框架之正则表达式URL误区