So, I started learning to code in Python and later Django. The first times it was hard looking at tracebacks and actually figure out what I did wrong and where the syntax error was. Some time has passed now and some way along the way, I guess I got a routine in debugging my Django code. As this was done early in my coding experience, I sat down and wondered if how I was doing this was ineffective and could be done faster. I usually manage to find and correct the bugs in my code, but I wonder if I should be doing it faster?

我通常只使用Django启用时提供的调试信息。当事情确实像我想象的那样结束时,我用一个语法错误破坏了代码流,并查看流中那个点的变量,以找出代码在哪里做了与我想要的不同的事情。

但这种情况还能改善吗?是否有一些更好的工具或方法来调试Django代码?


当前回答

另外一个建议。

您可以同时利用nosetests和pdb,而不是手动在视图中注入pdb.set_trace()。这样做的好处是,您可以在错误条件第一次启动时观察到它们,可能是在第三方代码中。

这是我今天的一个错误。

TypeError at /db/hcm91dmo/catalog/records/

render_option() argument after * must be a sequence, not int

....


Error during template rendering

In template /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/crispy_forms/templates/bootstrap3/field.html, error at line 28
render_option() argument after * must be a sequence, not int
18  
19          {% if field|is_checkboxselectmultiple %}
20              {% include 'bootstrap3/layout/checkboxselectmultiple.html' %}
21          {% endif %}
22  
23          {% if field|is_radioselect %}
24              {% include 'bootstrap3/layout/radioselect.html' %}
25          {% endif %}
26  
27          {% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
28  

      {% if field|is_checkbox and form_show_labels %}

现在,我知道这意味着我把表单的构造函数弄糊涂了,我甚至很清楚哪个字段有问题。但是,我可以使用pdb看到脆皮的形式是抱怨,在一个模板?

是的,我会。在nosetests上使用——pdb选项:

测试$ nosetests test_urls_catalog.py——pdb

一旦我碰到任何异常(包括优雅地处理的异常),pdb就会停止,我可以四处查看。

  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/forms.py", line 537, in __str__
    return self.as_widget()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/forms.py", line 593, in as_widget
    return force_text(widget.render(name, self.value(), attrs=attrs))
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py", line 513, in render
    options = self.render_options(choices, [value])
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py", line 543, in render_options
    output.append(self.render_option(selected_choices, *option))
TypeError: render_option() argument after * must be a sequence, not int
INFO lib.capture_middleware log write_to_index(http://localhost:8082/db/hcm91dmo/catalog/records.html)
INFO lib.capture_middleware log write_to_index:end
> /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py(543)render_options()
-> output.append(self.render_option(selected_choices, *option))
(Pdb) import pprint
(Pdb) pprint.PrettyPrinter(indent=4).pprint(self)
<django.forms.widgets.Select object at 0x115fe7d10>
(Pdb) pprint.PrettyPrinter(indent=4).pprint(vars(self))
{   'attrs': {   'class': 'select form-control'},
    'choices': [[('_', 'any type'), (7, (7, 'type 7', 'RECTYPE_TABLE'))]],
    'is_required': False}
(Pdb)         

现在,很明显,我对crispy field构造函数的choices参数是一个列表中的列表,而不是元组中的list/tuple。

 'choices': [[('_', 'any type'), (7, (7, 'type 7', 'RECTYPE_TABLE'))]]

整洁的事情是,这个pdb发生在脆皮的代码,而不是我的,我不需要手动插入它。

其他回答

我发现Visual Studio Code用于调试Django应用程序非常棒。标准的python启动。Json参数运行python manage.py,并附带调试器,因此你可以设置断点,并按自己的喜好逐步执行代码。

我使用pyDev与Eclipse真的很好,设置断点,进入代码,查看任何对象和变量的值,尝试它。

我使用PyCharm并一直支持它。我花了一点钱,但我不得不说我从中得到的好处是无价的。我尝试过从控制台调试,我确实很信任那些能做到这一点的人,但对我来说,能够直观地调试我的应用程序是很棒的。

我不得不说,PyCharm确实占用了很多内存。但话说回来,生活中没有什么好东西是免费的。他们刚刚发布了最新版本3。它也可以很好地与Django, Flask和谷歌AppEngine一起使用。所以,总而言之,我认为这是任何开发人员都可以拥有的一个非常方便的工具。

如果你还没有使用它,我建议你试用30天,看看PyCharm的强大功能。我相信还有其他可用的工具,比如Aptana。但我想我也喜欢PyCharm的外观。我觉得在那里调试我的应用程序很舒服。

我强烈推荐epdb(扩展Python调试器)。

https://bitbucket.org/dugan/epdb

我喜欢用epdb来调试Django或其他Python web服务器的一个原因是epdb.serve()命令。这将设置跟踪,并在您可以连接到的本地端口上提供该跟踪。典型用例:

我有一个视图,我想一步一步地讲。我将在我想要设置跟踪的位置插入以下内容。

import epdb; epdb.serve()

一旦执行了这段代码,我打开一个Python解释器并连接到服务实例。我可以分析所有的值,并使用标准pdb命令(如n, s等)逐级遍历代码。

In [2]: import epdb; epdb.connect()
(Epdb) request
<WSGIRequest
path:/foo,
GET:<QueryDict: {}>, 
POST:<QuestDict: {}>,
...
>
(Epdb) request.session.session_key
'i31kq7lljj3up5v7hbw9cff0rga2vlq5'
(Epdb) list
 85         raise some_error.CustomError()
 86 
 87     # Example login view
 88     def login(request, username, password):
 89         import epdb; epdb.serve()
 90  ->     return my_login_method(username, password)
 91
 92     # Example view to show session key
 93     def get_session_key(request):
 94         return request.session.session_key
 95

您可以在任何时候了解更多关于输入epdb帮助的信息。

如果希望同时为多个epdb实例提供服务或连接到多个epdb实例,可以指定监听的端口(默认为8080)。即。

import epdb; epdb.serve(4242)

>> import epdb; epdb.connect(host='192.168.3.2', port=4242)

如果没有指定,主机默认为'localhost'。我在这里介绍它是为了演示如何使用它来调试本地实例以外的东西,比如本地LAN上的开发服务器。显然,如果您这样做,请注意设置跟踪永远不会出现在您的生产服务器上!

作为一个快速提示,您仍然可以使用epdb执行与接受的答案相同的操作(import epdb;epdb.set_trace()),但我想强调一下服务功能,因为我发现它非常有用。

另外一个建议。

您可以同时利用nosetests和pdb,而不是手动在视图中注入pdb.set_trace()。这样做的好处是,您可以在错误条件第一次启动时观察到它们,可能是在第三方代码中。

这是我今天的一个错误。

TypeError at /db/hcm91dmo/catalog/records/

render_option() argument after * must be a sequence, not int

....


Error during template rendering

In template /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/crispy_forms/templates/bootstrap3/field.html, error at line 28
render_option() argument after * must be a sequence, not int
18  
19          {% if field|is_checkboxselectmultiple %}
20              {% include 'bootstrap3/layout/checkboxselectmultiple.html' %}
21          {% endif %}
22  
23          {% if field|is_radioselect %}
24              {% include 'bootstrap3/layout/radioselect.html' %}
25          {% endif %}
26  
27          {% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
28  

      {% if field|is_checkbox and form_show_labels %}

现在,我知道这意味着我把表单的构造函数弄糊涂了,我甚至很清楚哪个字段有问题。但是,我可以使用pdb看到脆皮的形式是抱怨,在一个模板?

是的,我会。在nosetests上使用——pdb选项:

测试$ nosetests test_urls_catalog.py——pdb

一旦我碰到任何异常(包括优雅地处理的异常),pdb就会停止,我可以四处查看。

  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/forms.py", line 537, in __str__
    return self.as_widget()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/forms.py", line 593, in as_widget
    return force_text(widget.render(name, self.value(), attrs=attrs))
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py", line 513, in render
    options = self.render_options(choices, [value])
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py", line 543, in render_options
    output.append(self.render_option(selected_choices, *option))
TypeError: render_option() argument after * must be a sequence, not int
INFO lib.capture_middleware log write_to_index(http://localhost:8082/db/hcm91dmo/catalog/records.html)
INFO lib.capture_middleware log write_to_index:end
> /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/forms/widgets.py(543)render_options()
-> output.append(self.render_option(selected_choices, *option))
(Pdb) import pprint
(Pdb) pprint.PrettyPrinter(indent=4).pprint(self)
<django.forms.widgets.Select object at 0x115fe7d10>
(Pdb) pprint.PrettyPrinter(indent=4).pprint(vars(self))
{   'attrs': {   'class': 'select form-control'},
    'choices': [[('_', 'any type'), (7, (7, 'type 7', 'RECTYPE_TABLE'))]],
    'is_required': False}
(Pdb)         

现在,很明显,我对crispy field构造函数的choices参数是一个列表中的列表,而不是元组中的list/tuple。

 'choices': [[('_', 'any type'), (7, (7, 'type 7', 'RECTYPE_TABLE'))]]

整洁的事情是,这个pdb发生在脆皮的代码,而不是我的,我不需要手动插入它。