Django HTML POST 参数导致 NoReverseMatch

Posted

技术标签:

【中文标题】Django HTML POST 参数导致 NoReverseMatch【英文标题】:Django HTML POST parameters causes NoReverseMatch 【发布时间】:2017-05-14 15:45:15 【问题描述】:

我有一个带有两个下拉列表的 html 帖子,我想将这些列表中选定的 Country 发送到 views.py 中的 search() 方法,然后将我发送到 results 视图。每当我添加 governmentlocation 作为 html POST 操作的参数或在搜索正则表达式中添加它们的值时,我尝试这个我从我的 index 页面得到一个 NoReverseMatch

未找到带有参数“(”,“”)和关键字参数“”的“搜索”。尝试了 1 种模式:['search/(?P[A-Z]3)/(?P[A-Z]3)/']

我不会因为我做错了什么而导致这个错误。 (见代码中的cmets)

应用名称/views.py:

from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from .models import Country, Embassy
from django.template import loader
from django.urls import reverse


def index(request):
    country = Country.objects.filter()
    template = loader.get_template('appname/index.html')
    context = 'countries': country
    return render(request, 'appname/index.html', context)

def results(request, government, location):
    return HttpResponse("Here are the Embassies sent by %s, located in %s." % (government, location))

def search(request):
    countries  = Country.objects.all()
    form = request.POST
    if request.method == 'POST':
        try:
            selected_government = get_object_or_404(pk=request.POST['government'])
        except (KeyError, Country.DoesNotExist):
            return render(request, 'appname/index.html', 
                'error_message': "You didn't select a government.",
            )
        try:
            selected_location = get_object_or_404(pk=request.POST['location'])
        except (KeyError, Country.DoesNotExist):
            return render(request, 'appname/index.html', 
                'error_message': "You didn't select a location.",
            )
        else:
            return HttpResponseRedirect(reverse('appname:results', args=(selected_government.code,selected_location.code,)))

应用名称/模板/应用名称/index.html:

% if error_message %<p><strong> error_message </strong></p>% endif %

# government and location in the form action causes a NoReverse Match
<form action="% url 'appname:search' government location %" method="POST"> 
    % csrf_token %
    <label>Find Embassies sent by</label>
    <select name="government">
        % for entry in countries %
            <option value=" entry.code "> entry.name </option>
        % endfor %
    </select>
    <label>that are located in</label>
    <select name="location">
        % for entry in countries %
            <option value=" entry.code "> entry.name </option>
        % endfor %
    </select>
    <input type="submit" value="Search" />
</form>

urls.py:

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^', include('appname.urls')),
    url(r'^appname/', include('appname.urls')),
    url(r'^admin/', admin.site.urls),
]

应用名称/urls.py:

from django.conf.urls import url

from . import views

app_name = 'appname'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<embassy_id>[0-9]+)/$', views.embassy_info, name='embassy_info'),
    url(r'^(?P<code>[A-Z]3)/$', views.country_info, name='country_info'),
    url(r'^find/(?P<government>[A-Z]3)/(?P<location>[A-Z]3)/$', views.results, name='results'),
    # the government and location values in search regex also cause a NoReverse Match   
    url(r'^search/(?P<government>[A-Z]3)/(?P<location>[A-Z]3)/', views.search, name='search'),
]

应用名称/models.py:

from django.db import models

class Country(models.Model):
    code = models.CharField(primary_key=True, max_length=3)
    name = models.CharField(max_length=50, db_column="Name")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Country'
        verbose_name_plural = 'Countries'


class Embassy(models.Model):
    government = models.ForeignKey(Country, on_delete=models.CASCADE, related_name="government")
    location = models.ForeignKey(Country, on_delete=models.CASCADE, related_name="location")
    name = models.CharField(max_length=200, db_column="Name")
    street_address = models.CharField(max_length=200, db_column="Address")
    city = models.CharField(max_length=50, db_column="City")
    phone_number = models.IntegerField(default=-1, db_column="Phone Number")
    fax_number = models.IntegerField(null=True, blank=True, db_column="Fax Number")
    email_address = models.CharField(max_length=200, db_column="Email")
    website = models.CharField(max_length=200, db_column="Link")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'Embassy'
        verbose_name_plural = 'Embassies'

【问题讨论】:

【参考方案1】:

它不是那样工作的。 url 标签的参数——实际上就像任何模板标签一样——必须来自渲染时传递给模板的上下文。但是您正在尝试从表单本身动态使用值。

您应该从 URL 模式中完全删除参数。无论如何,您都没有在视图中使用它们,因为您从 request.POST 正确获取了值。

url(r'^search/$', views.search, name='search'),

...

<form action="% url 'search' %" ...

【讨论】:

现在我从views.py 中的selected_government = get_object_or_404(pk=request.POST['government']) 行得到get_object_or_404() missing 1 required positional argument: 'klass' 错误,但不确定它是什么意思。在我的代码中没有使用“klass” 你需要告诉那个函数使用什么模型:get_object_or_404(Government, pk=request.POST['government']). 我认为你的意思是Country,但你没看错。【参考方案2】:

您需要使用ModelChoiceField 创建一个表单。

forms.py

from django import forms
from models import Country

class SearchForm(forms.Form):
    government = forms.ModelChoiceField(queryset=Country.objects.all(), to_field_name="code", label="Find Embassies sent by")
    location = forms.ModelChoiceField(queryset=Country.objects.all(), to_field_name="code", label="that are located in")

views.py

from forms import SearchForm

def index(request):
    form = SearchForm()
    context = 'form': form
    return render(request, 'appname/index.html', context)


def search(request):
    form = SearchForm(request.POST or None)
    if request.POST and form.is_valid():
        govt = form.cleaned_data.get('government')
        loc = form.cleaned_data.get('location')
        return HttpResponseRedirect(reverse('appname:results', kwargs="government": govt.code, "location": loc.code))
    else:
        context = 'form': form
        return render(request, 'appname/index.html', context)

appname/urls.py 中 添加此网址

url(r'^search/$', views.search, name='search'),

index.html

<form method="post" action=% url 'appname:search' %>
    % csrf_token %
     form.as_p 
    <input type="submit" value="Search" />
</form>

【讨论】:

【参考方案3】:

Django URL 解析器反向将关键字参数作为参数

reverse('search', kwargs='government':goverment.code, 'location':location.code)

希望对你有帮助

【讨论】:

谢谢,但它似乎不起作用,我仍然遇到同样的错误。 您没有在基本应用程序 url 中配置命名空间。所以你不应该需要 appname 作为前缀。更新了我的答案 你的意思是app_name = 'appname' 没有在你的基础应用 urls.py 中包含类似 include('appname.urls'), namespace='appname') 你是对的,但这似乎与我的问题无关。尤其是现在已经解决了。

以上是关于Django HTML POST 参数导致 NoReverseMatch的主要内容,如果未能解决你的问题,请参考以下文章

django入门 04 初探GET/POST 设计登录页面

Django按钮ajax点击

django HttpResponseRedirect怎么传递参数

django HttpResponseRedirect怎么传递参数

Django:重构通过 $.post 发送的结构化参数

Python 装饰器检查 Django 上的 POST 参数