为什么当我交换 url 模式成员的顺序时错误会有所不同

Why do errors differ when I interchange the order of the members of url patterns

Note: I'm not requesting for a help to fix the errors, but to ask the reason why they differ by interchanging the order of url patterns.

以下是我的 urls.py 我的 django 应用程序 (basic_app) 的样子:

from django.urls import path, re_path
from basic_app import views

app_name = 'basic_app'

urlpatterns = [
    path('', views.SchoolListView.as_view(), name='list'),
    re_path(r'^(?P<pk>[-\w]+)/$', views.SchoolDetailView.as_view(), name='detail'),
    path('create/', views.SchoolCreateView.as_view(), name='create'),
]

当我 运行 服务器并输入 url http://127.0.0.1:8000/basic_app/create/ 时,它抛出以下错误:

ValueError at /basic_app/create/
Field 'id' expected a number but got 'create'.
Request Method: GET
Request URL:    http://127.0.0.1:8000/basic_app/create/
Django Version: 3.2.4
Exception Type: ValueError
Exception Value:    
Field 'id' expected a number but got 'create'.

有趣的是,我将第二和第三个 url 模式的顺序互换如下:

from django.urls import path, re_path
from basic_app import views

app_name = 'basic_app'

urlpatterns = [
    path('', views.SchoolListView.as_view(), name='list'),
    path('create/', views.SchoolCreateView.as_view(), name='create'),
    re_path(r'^(?P<pk>[-\w]+)/$', views.SchoolDetailView.as_view(), name='detail'),
]

我得到了一个不同的错误:

ImproperlyConfigured at /basic_app/create/
Using ModelFormMixin (base class of SchoolCreateView) without the 'fields' attribute is prohibited.
Request Method: GET
Request URL:    http://127.0.0.1:8000/basic_app/create/
Django Version: 3.2.4
Exception Type: ImproperlyConfigured
Exception Value:    
Using ModelFormMixin (base class of SchoolCreateView) without the 'fields' attribute is prohibited.

我是django的新手,对这个事件很好奇。为什么 python 让 create/ 去检查下一个模式,因为它不符合第一个模式?


我的 views.py 文件如下所示:

from django.shortcuts import render
from django.views.generic import (
    View,
    TemplateView,
    ListView,
    DetailView,
    CreateView,
    UpdateView,
    DeleteView
)
from . import models


# Create your views here.
class IndexView(TemplateView):
    template_name = 'index.html'


class SchoolListView(ListView):
    context_object_name = 'schools'
    model = models.School


class SchoolDetailView(DetailView):
    context_object_name = 'school_detail'
    model = models.School
    template_name = 'basic_app/school_detail.html'


class SchoolCreateView(CreateView):
    model = models.School

Django 旨在匹配 url 的自上而下。如果您因此访问 /basic_app/create/,并且带有 SchoolDetailView 的规则是第一个,它将触发该视图,因为 create/ 与正则表达式 (?P<pk>[-\w+])/$ 匹配。由于您的对象的主键可能是一个 AutoField,因此将 create/pk 匹配是没有意义的,因为我们希望它是一个整数。

另一个问题是你的SchoolCreateView配置不正确,你需要指定CreateView中将使用哪些字段,所以我们可以用:

来实现
class SchoolCreateView(CreateView):
    model = models.School
    <strong>fields = '__all__'</strong>

我们可以改进详细视图的 re_path 以仅使用 int 触发,而不是任意 slug:

re_path(r'^(?P<pk><strong>\d+</strong>)/$', views.SchoolDetailView.as_view(), name='detail'),

或使用路径转换器:

path(r'<strong><int:pk></strong>/', views.SchoolDetailView.as_view(), name='detail'),