【问题标题】:Explanation on Django's request processing - Why does it select one urlpattern from anotherDjango的请求处理说明-为什么它从另一个urlpattern中选择一个urlpattern
【发布时间】:2021-01-09 16:46:55
【问题描述】:

所以我正在做一个涉及 Django 的免费在线课程,并且在 Django 如何处理请求方面遇到了一些相当混乱的问题。我的 Django 应用程序有一个模块,在这个模块中,我基本上有两个页面,我正在生成这两个页面,它们都继承自布局模板。有一个索引页面(包含指向各个条目的链接)和一个显示每个条目内容的条目页面。有两种方法可以进入入口页面。您可以直接单击索引页面上的链接,也可以在索引页面上的搜索栏中键入。如果名称与搜索栏中的条目匹配,它将带您进入该条目页面。到达入口页面的每种方法在 urls.py 文件中都有自己的 url 模式,并且在 views.py 文件中每种方法都有自己的路由功能。发生的情况是,无论在搜索栏中输入什么内容,它都只会使用用于直接单击索引页面中的条目链接的路径,而不是用于搜索的路径。这是我的 html 文件:

布局(包含用于搜索的导航栏:

<html lang="en">
    <head>
        <title>{% block title %}{% endblock %}</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
        <link href="{% static 'encyclopedia/styles.css' %}" rel="stylesheet">
    </head>
    <body>
        <div class="row">
            <div class="sidebar col-lg-2 col-md-3">
                <h2>Wiki</h2>
                <form action="{% url 'encyc:search' %}" method="GET">
                    <input class="search" type="text" name="q" placeholder="Search Encyclopedia">
                </form>
                <div>
                    <a href="{% url 'encyc:index' %}">Home</a>
                </div>
                <div>
                    Create New Page
                </div>
                <div>
                    Random Page
                </div>
                {% block nav %}
                {% endblock %}
            </div>
            <div class="main col-lg-10 col-md-9">
                {% block body %}
                {% endblock %}
            </div>
        </div>

    </body>
</html>

索引页面:

{% extends "encyclopedia/layout.html" %}

{% block title %}
    Encyclopedia
{% endblock %}

{% block body %}
    <h1>All Pages</h1>

    <ul>
        {% for entry in entries %}
            <li><a href="{% url 'encyc:display' entry %}">{{ entry }}</a></li>
        {% endfor %}
    </ul>

{% endblock %}

和入口页面:

{% extends "encyclopedia/layout.html" %}

{% block title %}
    {{ name }}
{% endblock %}

{% block body %}

    {{ entry | safe }}

{% endblock %}

这是我的 urls.py 文件:

from django.urls import path
from . import views

app_name = "encyc"
urlpatterns = [
    path("", views.index, name="index"),
    # variable names for each page
    path("<str:name>", views.display, name="display"),
    path("search", views.search, name="search")
]

这是我的views.py文件:

from django.shortcuts import render
import markdown2
from . import util
import logging
logging.basicConfig(filename='encyclopedia/log.log', encoding='utf-8', level=logging.DEBUG)

def index(request):
    return render(request, "encyclopedia/index.html", {
        "entries": util.list_entries()
    })

def display(request, name):
    logging.debug('request info: ')
    logging.debug(request)
    logging.debug('request path info: ')
    logging.debug(request.path_info)
    # convert name to all lowercase and then capitalize
    entry = util.get_entry(name.lower().capitalize())
    if (entry != None):
        entry = markdown2.markdown(entry)
        return render(request, "encyclopedia/entry.html", {
        "name": name,
        "entry": entry
        })
    else:
        return render(request, "encyclopedia/error.html")

def search(request):
    logging.debug('request info: ')
    logging.debug(request)
    logging.debug('request path info: ')
    logging.debug(request.path_info)
    name = request.GET['q'].lower().capitalize()
    entry = util.get_entry(name)
    entry = markdown2.markdown(entry)
    return render(request, "encyclopedia/entry.html", {
        "name": name,
        "entry": entry
    })

这是整个 Django 应用程序的 urls.py 文件:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include("encyclopedia.urls")),
    path('wiki/', include("encyclopedia.urls"))
]

最终,这里的修复是在我的 urls.py 文件中的单个模块。线

path("<str:name>", views.display, name="display")

应该是

path("wiki/<str:name>", views.display, name="display")

这开始了我的探索,以了解正在发生的事情以及为什么会发生这种情况。在深入Django's documentation on request processing 之后,似乎 Django 接受了一个请求,扫描了 url 模式,并根据 'path_info' 属性选择了第一个匹配项。所以现在我知道它只使用显示路由而不是搜索路由的原因是它以某种方式将此属性与该路由匹配,并且从未真正到达搜索 urlpattern。这就引出了一个问题,为什么它基于“path_info”进行匹配。我决定设置一个记录器并查看请求信息是什么以及 path_info。这是修复实施之前的日志:

DEBUG:root:<WSGIRequest: GET '/CSS'>
DEBUG:root:request path info: 
DEBUG:root:/CSS
DEBUG:root:request info: 
DEBUG:root:<WSGIRequest: GET '/search?q=css'>
DEBUG:root:request path info: 
DEBUG:root:/search

这是修复后的日志

DEBUG:root:request info: 
DEBUG:root:<WSGIRequest: GET '/wiki/CSS'>
DEBUG:root:request path info: 
DEBUG:root:/wiki/CSS
DEBUG:root:request info: 
DEBUG:root:<WSGIRequest: GET '/search?q=css'>
DEBUG:root:request path info: 
DEBUG:root:/search

在我看来,路径信息只不过是 url 模式中指定的路由。我仍然不明白为什么此修复程序有效。为什么在我的显示路由 urlpattern 前添加 'wiki/' 允许 Django 现在正确匹配 path_info ,而以前它不能。另一个问题是为什么 Django 不使用 urlpattern 中指定的 name 属性来匹配所需的路由?我在 html 中指定了我想要“搜索”的 url,但它仍然选择了“显示”的 url。如果它只是与我提供的名称匹配,那么在选择适当的 url 时不应该清楚任何歧义吗?我知道这是一篇冗长的文章,但如果您能深入了解 Django 如何处理这些请求以及为什么这个特定的修复对我有用,我们将不胜感激!

【问题讨论】:

    标签: python html css django


    【解决方案1】:

    我认为需要分开两个步骤:

    1. 在 html 中呈现 {% url .... %} 标记,这会导致页面中的最终 url
    2. 当用户点击 url 时发送请求 两者都链接到 urls.py->path

    广告 1) 对于 display hrefs,您的 url 是根据名称“display”和您在路径匹配字符串中也称为“name”的属性创建的“反向”。所以 {% url "display" "css" %} 导致 "server_name/css"。 搜索字段通过名称“=”搜索的路径定义完全相同。 所以到目前为止一切都很好。您可以在 DEBUG 数据中看到正确创建的 url/请求。

    Ad 2) 根据请求,django 仅获取调用的 url,并逐步遍历所有路径语句以找到匹配项。 这是您的问题,因为您的模式不是唯一的:

    path("<str:name>",  ....
    

    将匹配 /css 也匹配 /search?... 因为 str 匹配任何以下字符串,包括“search?...”。

    你需要先选择目标,然后给参数like

    Path("display/<str:parameter>" .....
    Path("search" ...   )
    

    那么搜索与前面的显示路径不再匹配了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 1970-01-01
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多