Python Django不匹配URL,没有反向匹配

Python Django不匹配URL,没有反向匹配,python,django,Python,Django,我在Django项目中使用基于TDD的方法,这是一个自制材料的数据库。通过功能测试和单元测试,我已经能够添加一个hops记录。我遇到的问题是更新视图功能(编辑现有记录)。我以前在基于类的视图中这样做过,但遇到了一些无法避免的错误,这就是为什么我使用TDD/函数视图方法,而不是直接使用CBV 我当前收到以下错误,表明我的视图beerdb/edit/(?p\\d+)/hops/$没有反向匹配。因此,我在我的跃点模型上创建了一个get_absolute_url方法: def get_absolute_

我在Django项目中使用基于TDD的方法,这是一个自制材料的数据库。通过功能测试和单元测试,我已经能够添加一个hops记录。我遇到的问题是更新视图功能(编辑现有记录)。我以前在基于类的视图中这样做过,但遇到了一些无法避免的错误,这就是为什么我使用TDD/函数视图方法,而不是直接使用CBV

我当前收到以下错误,表明我的视图
beerdb/edit/(?p\\d+)/hops/$
没有反向匹配。因此,我在我的跃点模型上创建了一个get_absolute_url方法:

def get_absolute_url(self):
    return reverse('updatehops', kwargs={'pk': self.id})
要返回该反向url,请执行以下操作:

django.core.urlresolvers.NoReverseMatch: Reverse for 'updatehops' with arguments '()' and keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['beerdb/edit/(?P<pk>\\d+)/hops/$']
我的其他项目详情如下。有人能指出我哪里出了问题吗?我还认为我的url.py可能需要一些修改。我不太明白如何用模板返回反向url。我已经查看了render、render_to_响应、redirect和HttpResponseRedirect对象,但没有看到如何返回该上下文。在基于类的视图中,我会调用super方法并获取上下文数据,将主键添加到“action”,但我不知道如何在这里应用它

项目详细信息

url.py

urlpatterns = [
    url(r'^$', views.homebrewmain, name='beerdb_main'),
    url(r'^hops/$', views.hops, name='hops_list'),
    url(r'^add/hops/$', views.addhops, name='addhops'),
    url(r'^edit/(?P<pk>\d+)/hops/$', views.updatehops, name='updatehops')
]
编辑:我已更新了我的查看函数,以返回反向url的重定向,而不使用点符号:

def updatehops(request, pk):

    hop_record = Hop.objects.filter(pk=pk)[0]
    edit_form = HopForm(request.POST or None, instance=hop_record)

    if request.method == 'POST':
        if edit_form.is_valid():
            edit_form.save()
            success_url = reverse('hops_list')
        return HttpResponseRedirect(success_url)
    hop_form_url = reverse('updatehops', kwargs={'pk': hop_record.id})
    return redirect(hop_form_url)
正如我在下面的评论中所指出的,如果我在响应上断言status_code=302,那么测试就通过了,但是我需要200来确保我得到了呈现的表单,这样我就可以访问响应中的内容,更改一些数据,并在稍后编写测试的其余部分时重新保存

更新:在做了一些研究之后,我已经修改了url,以便它现在在hop\u id中传递,而不是

url(r'^edit/(?P\d+)/hops/$,views.updatehops,name='updatehops'),
我仍然收到错误,但它已收到错误消息中的pk:

django.core.urlresolvers.NoReverseMatch: Reverse for 'updatehops' with arguments '()' and keyword arguments '{'pk': 7}' not found. 1 pattern(s) tried: ['beerdb/edit/(?P<hop_id>\\d+)/hops/$']
django.core.urlresolvers.NoReverseMatch:找不到参数为“()”且关键字参数为“{pk':7}”的“updatehops”的反向。已尝试1个模式:['beerdb/edit/(?P\\d+)/hops/$']
编辑2:我已将“pk”添加回URL,添加回溯

回溯

模板错误:
在template/Path/To/Site/Site/homebrewdatabase/templates/homebrewdatabase/hops.html中,第23行出现错误
找不到参数为“()”且关键字参数为“{pk:”}”的“updatehops”的反转。已尝试1个模式:['beerdb/edit/(?P\\d+)/hops/$']
13:{%include'homebrewdatabase/addhops.html%}
14 : 
15 :         
16 :         
17 :             
18 :                
19 :                    
20:&次;
21:添加啤酒花
22 :               
23 :               
24 :                 
25:{form.as_p}
26:{%csrf_令牌%}
27 :                 
28 :               
29:结束
30:提交
31 :               
32 :               
33 :             
编辑3:

您必须这样做:
reverse('updatehops')


选中

如果希望测试客户端遵循重定向,请使用
follow=True

response = self.client.post(
        '/beerdb/add/hops/',
        data={...}, 
        follow=True, 
   ) 
然后可以检查响应的内容。如果要测试重定向,可以使用而不是检查状态代码

这里有几个关于反向URL的提示。首先,使用url模式名称,例如
updatehops
,而不是视图的完整路径
“homebrewdatabase.views.updatehop”
。第二,确保你的kwargs匹配。url中有
hop\u id
。所以你需要

reverse('updatehops', kwargs={'hop_id': hop_record.id})
测试代码的上一行不应该是beerdb_main,而应该是beerdb


仅供参考:我指的是代码的测试部分。

反向函数(以及模板中的
url
标记)采用您在url中给出的名称,而不是视图的虚线模块路径。名称空间由冒号(
)分隔。我已将第一个参数更新为view函数,但随后必须重定向到反向视图,如果我断言响应状态代码为302,则测试将通过,但我尝试获得200。在这一点上,我被一个没有内容的HttpResponseRedirect对象困住了,所以当我对测试的其余部分进行更正时,我无法编辑表单。@sandWhat Heat,what's in your view。如果它返回重定向响应,301/302/etc将是您将获得的状态代码。。。应该期待,同意。我不知道如何使用表单作为上下文呈现的模板在视图中返回反向url。视图肯定需要修复,我只是不确定如何修复。模板中的问题是url标记中的
hop.id
。是否确实在呈现模板时通过了
hop
。你还没有展示你的观点的那一部分。谢谢,这是一个很好的发现,它并不能完全解决问题,但我会在这里发布我的回溯。我希望这会有所帮助。我还应该提到,我已经用
returnreverse('updatehops',kwargs={'pk':self.id})更新了get_absolute\u url
。我已经发布了回溯(我添加了名称空间)。我选择了这个答案,添加了一些要点。不需要获取绝对url。指向一个模态的链接,我把它放回页面进行调试,但是我在一个名为updatehops.html的文件中有一个实际的模态。视图正在呈现updatehops.html文件,但我没有在那里将表单url更新为{{action}},而是我以前使用的错误url,url标记。我不需要专注于返回反向URL,Django只是找不到它,因为它没有得到正确的操作。模态没有出现,但是这个问题超出了本文的范围。谢谢陛下
django.core.urlresolvers.NoReverseMatch: Reverse for 'updatehops' with arguments '()' and keyword arguments '{'pk': 7}' not found. 1 pattern(s) tried: ['beerdb/edit/(?P<hop_id>\\d+)/hops/$']
Template error:
In template /Path/To/Site/Site/homebrewdatabase/templates/homebrewdatabase/hops.html, error at line 23
   Reverse for 'updatehops' with arguments '()' and keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['beerdb/edit/(?P<pk>\\d+)/hops/$']   
   13 :         {% include 'homebrewdatabase/addhops.html' %}
   14 : 
   15 :         <!--Modal data begins here to edit hops-->
   16 :         <div class="modal fade" id="updatehops" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
   17 :             <div class="modal-dialog" role="document">
   18 :                <div class="modal-content">
   19 :                    <div class="modal-header">
   20 :                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
   21 :                        <h4 class="modal-title" id="myModalLabel">Add Hops</h4>
   22 :               </div>
   23 :               <form action=" {% url 'homebrewdatabase:updatehops' pk=hop.id %} " method="POST">
   24 :                 <div class="modal-body">
   25 :                     {{ form.as_p }}
   26 :                     {%  csrf_token %}
   27 :                 </div>
   28 :               <div class="modal-footer">
   29 :                 <button type="button" id="close" class="btn btn-default" data-dismiss="modal">Close</button>
   30 :                 <button type="submit" id="submit" class="btn btn-primary">Submit</button>
   31 :               </form>
   32 :               </div>
   33 :             </div>
response = self.client.post(
        '/beerdb/add/hops/',
        data={...}, 
        follow=True, 
   ) 
reverse('updatehops', kwargs={'hop_id': hop_record.id})
response = self.client.get('/beerdb/edit/%d/hops/' % hop_instance.id)