如何在Django中进行调试,好方法?[关闭]


587

因此,我开始学习使用Python和更高版本的Django进行编码。第一次很难查看回溯,实际上要弄清楚我做错了什么以及语法错误在哪里。现在已经过去了一段时间,而且我想我已经有了调试Django代码的例程。由于这是我编码经验的早期,所以我坐下来,想知道自己的做法是否无效,并且可以更快地完成。我通常设法找到并纠正代码中的错误,但是我想知道是否应该更快地执行该操作?

我通常只使用Django启用时提供的调试信息。当事情按我预期的那样结束时,我因语法错误而使代码流中断很多,然后查看流中该点的变量以找出其中的代码在做什么,而不是我想要的。

但这可以改善吗?是否有一些好的工具或更好的方法来调试Django代码?


2
我喜欢用Django的调试工具,它非常福
迭戈维尼修斯

1
或使用Visual Studio Code的内置Python调试器,如此处所述code.visualstudio.com/docs/python/tutorial-django
Nick T

Answers:


536

有很多方法可以做到,但是最直接的方法就是简单地使用Python调试器。只需将以下行添加到Django视图函数中:

import pdb; pdb.set_trace()

要么

breakpoint()  #from Python3.7

如果尝试在浏览器中加载该页面,浏览器将挂起,并且提示您对实际执行的代码进行调试。

但是,还有其他选择(我不推荐使用):

* return HttpResponse({variable to inspect})

* print {variable to inspect}

* raise Exception({variable to inspect})

但是强烈建议所有类型的Python代码都使用Python调试器(pdb)。如果你已经到PDB,你想也想看看IPDB使用IPython中进行调试。

对pdb的一些更有用的扩展是

pdb ++,由 Antash建议。

pudb,由 PatDuJour建议。

Seafangs建议在Django中使用Python调试器


64
+1用于建议pdb。但是,值得注意的是,这仅在本地计算机上使用开发服务器时才有效,因为提示将出现在控制台中。
丹尼尔·罗斯曼

12
另请参见django-pdb,其答案如下。给你manage.py runserver --pdbmanage.py test --pdb命令。
汤姆·克里斯蒂

4
@Daniel,请参阅rconsole,了解如何将控制台集成到已经运行的python实例中。
Phob

12
也请查看ipythonIpdb随附的ipython,具有制表符补全,彩色语法等功能:-)。
hobbes3'4

3
我发现您的答案很有用,但是当我尝试调试测试时,Django永远挂在断点上。所以,我看了一下,发现翔实的文章,帮助我了:v3.mike.tig.as/blog/2010/09/14/pdb
driftcatcher

228

我真的很喜欢Werkzeug的交互式调试器。它与Django的调试页面相似,不同之处在于您在回溯的每个级别上都获得了一个交互式shell。如果使用django-extensions,则会得到一个runserver_plus管理命令,该命令启动开发服务器,并为您提供Werkzeug的异常调试器。

当然,您只应在本地运行此命令,因为它使拥有浏览器的任何人都有权在服务器的上下文中执行任意python代码。


2
是否可以在浏览器中显示的交互式控制台中使用制表符完成功能?“ Tab”只是将我们带到下一个打开的控制台,我想知道是否有按键组合,但我找不到。
阿里尔(Ariel)2015年

@Ariel werkzeug调试器没有选项卡完成。
哈肯·里德(HåkenLid),2015年

如果要对API进行调试,则可以尝试使用django-rundbg,它会为Werkzeug调试器增加一些扭曲。
elpaquete

最多只能到python 3.3
Timo

166

模板标记的小工具:

@register.filter 
def pdb(element):
    import pdb; pdb.set_trace()
    return element

现在,您可以在模板内执行{{ template_var|pdb }}并输入一个pdb会话(假设您正在运行本地devel服务器),您可以在其中检查element您的心脏内容。

这是查看对象到达模板时发生了什么情况的一种很好的方法。


1
这很棒。如果遇到模板问题,您可以做的另一件事是切换到jinja2(通过棺材加载)-这是django模板的扩展,我认为这是一种改进。它还比django更好地将模板和模板继承集成到回溯框架中。
fastmultiplication 2012年

好可爱 不幸的是,很难看到一种干净的方法将其集成到代码库中,该代码库会拒绝任何提交,包括pdb的导入。
乔恩·基帕尔斯基

83

有一些工具可以很好地协作,并且可以使您的调试任务更轻松。

最重要的是Django调试工具栏

然后,您需要使用Python 日志记录工具进行良好的日志记录。您可以将日志输出发送到日志文件,但是更简单的选择是将日志输出发送到firepython。要使用此功能,您需要使用带有firebug扩展名的Firefox浏览器。Firepython包含一个firebug插件,该插件将在Firebug标签中显示所有服务器端日志。

Firebug本身对于调试您开发的任何应用程序的Javascript方面也至关重要。(假设您当然有一些JS代码)。

我还喜欢使用django-viewtools通过pdb交互式地调试视图,但是我并没有那么多地使用它。

还有诸如推土机之类的更有用的工具来跟踪内存泄漏(SO的答案中也提供了其他一些很好的建议来进行内存跟踪)。


65

我使用PyCharm(与Eclipse相同的pydev引擎)。确实可以帮助我直观地逐步查看我的代码并查看正在发生的事情。


2
最好的是,它可以正常工作并且完全直观。只需单击一行的左侧,然后单击调试按钮。如果您想更好地了解内部代码的工作原理,那么它也适用于Django源代码。我花了一段时间才注意到它,但是您可以在文件导航器的“外部库”文件夹中的任何代码中放置断点。
Michael Bylstra 2012年

6
值得一提的是,PyCharm在幕后使用PyDev调试器来获得荣誉。
Medeiros


44

到目前为止,几乎所有内容都已提及,因此,我仅补充一点,而不是pdb.set_trace()可以使用ipdb.set_trace()(它使用iPython),因此功能更强大(自动完成功能和其他功能)。这需要ipdb包,因此您只需要pip install ipdb


2
我建议使用pdb ++,它提供了非常有用的粘滞模式。
Sandeep

34

我推django-pdbPyPI中。这是一个简单的应用程序,这意味着您不必每次想进入pdb都需要编辑源代码。

安装只是...

  1. pip install django-pdb
  2. 添加'django_pdb'到您的INSTALLED_APPS

您现在可以运行:manage.py runserver --pdb在每个视图的开始处进入pdb ...

bash: manage.py runserver --pdb
Validating models...

0 errors found
Django version 1.3, using settings 'testproject.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

GET /
function "myview" in testapp/views.py:6
args: ()
kwargs: {}

> /Users/tom/github/django-pdb/testproject/testapp/views.py(7)myview()
-> a = 1
(Pdb)

并运行:manage.py test --pdb在测试失败/错误时进入pdb ...

bash: manage.py test testapp --pdb
Creating test database for alias 'default'...
E
======================================================================
>>> test_error (testapp.tests.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File ".../django-pdb/testproject/testapp/tests.py", line 16, in test_error
    one_plus_one = four
NameError: global name 'four' is not defined
======================================================================

> /Users/tom/github/django-pdb/testproject/testapp/tests.py(16)test_error()
-> one_plus_one = four
(Pdb)

该项目托管在GitHub上,当然欢迎您贡献。


3
如果您可以指定要在其处中断的文件/行号(而不仅仅是视图),那将是很棒的。
2011年

我可以在代码中留下一些注释,例如注释在生产中是惰性的。也许这不是一个坏的天堂,但有效地剥离和应用断断续续的做法会很棒。
甘油2012年

我最近安装了该软件,但是直到今天,我才发现要在Tom的django-pdb所记录的开发设置中配置“ POST_MORTEM = True”。现在,我可以继续前进,当情况恶化时,我会直接转到问题所在的位置。谢谢汤姆!
约瑟夫·希迪

21

调试python的最简单方法是使用PTVS(适用于Visual Studio的Python工具),尤其是对于使用Visual Studio的程序员而言。步骤很简单:

  1. http://pytools.codeplex.com/下载并安装
  2. 设置断点并按F5。
  3. 您的断点被击中,您可以像调试C#/ C ++程序一样轻松地查看/更改变量。
  4. 就这样 :)

如果要使用PTVS调试Django,则需要执行以下操作:

  1. 在“项目设置”的“常规”选项卡中,将“启动文件”设置为“ manage.py”,这是Django程序的入口点。
  2. 在项目设置-调试选项卡中,将“脚本参数”设置为“ runserver --noreload”。关键是这里的“ --noreload”。如果您不设置它,您的断点将不会被击中。
  3. 好好享受。

1
谢谢,效果很好。--noreload是我们所需要的
Tom Gruner

是否有要在远程服务器上调试的功能-与我目前使用的Eclipse PyDev类似?
Daniel Sokolowski

我对此有疑问。我按照您的步骤进行,但仍然无法正常工作。它仅在* .py文件的断点处停止,而不在* .html文件的断点处停止。
blfuentes 2014年

16

我将pyDev与Eclipse 搭配使用非常好,设置断点,进入代码,查看任何对象和变量的值,然后尝试。


您必须通过eclipse运行开发服务器(以节省精力进行调试)。PyDev声称具有远程调试功能,但从未使用过它,所以我无法真正说出开发经验的质量。详细信息:pydev.org/manual_adv_remote_debugger.html
synthesizerpatel

2
PyDev的远程调试器可与Django的dev服务器完美配合。只要确保您具有“当文件更改时,自动重新加载模块?” PyDev的“运行/调试”设置中的“已禁用”选项。否则,开发服务器和pydev都将在调试时尝试重新加载代码,这使他们都非常困惑。
coredumperror 2014年

12

我使用PyCharm并一直坚持下去。它花了我一点钱,但我不得不说,我摆脱它的好处是无价的。我尝试从控制台进行调试,但我确实给予了很多荣誉,他们可以做到这一点,但是对我而言,能够直观地调试我的应用程序真是太好了。

我不得不说,PyCharm确实占用了大量内存。但是话又说回来,生活中没有什么是免费的。他们只是带有最新版本3。它在Django,Flask和Google AppEngine中也能很好地发挥作用。因此,总而言之,对于任何开发人员来说,这都是一个非常方便的工具。

如果您尚未使用它,建议您试用30天,以了解PyCharm的功能。我确定还有其他工具,例如Aptana。但是我想我也喜欢PyCharm的外观。我在那里调试我的应用程序感到非常自在。


它可能是我买的第一个IDE。在VM中调试项目听起来像是值得付出的魔术。
罗伯·格兰特

10

有时候,当我想探索一种特定的方法并且召唤pdb太麻烦时,我会添加:

import IPython; IPython.embed()

IPython.embed() 启动一个IPython shell,该shell可以从调用它的地方访问局部变量。


现在,我已经习惯在文件顶部执行此操作from IPython import embed,然后每当我想在代码中快速添加断点时,就编写embed()。节省时间。为了避免永远陷入循环,我这样做embed();exit();
Mayank Jaiswal,

@MayankJaiswal:我对Vim的键映射插入此片段(以及类似的片段pudb,并debugger;在JavaScript)为我编辑的文件。完成后,我只是dd(删除整行)以删除断点。这避免了将调试器导入行提交到版本控制中或必须首先在文件顶部预设导入的风险。
Lie Ryan

10

从我的角度来看,我们可以将常见的代码调试任务分解为三种不同的使用模式:

  1. 出现了一个异常runserver_plus'Werkzeug调试器进行了救援。在所有跟踪级别上运行自定义代码的能力是一个杀手er。而且,如果您完全陷入困境,则可以创建一个Gist,只需单击即可共享。
  2. 页面被渲染,但是结果是错误的:再次,Werkzeug摇摆不定。要在代码中创建断点,只需键入assert False要停止的位置。
  3. 代码工作不正确,但快速浏览无济于事。最有可能是算法问题。叹。然后,我通常火了调试器控制台PuDBimport pudb; pudb.set_trace()。与[i] pdb相比,主要优点是PuDB(看起来像80年代)使设置自定义监视表达式变得轻而易举。使用GUI调试一堆嵌套循环要简单得多。

啊,是的,模板的问题。最常见的问题(对我和我的同事而言)是错误的上下文:您没有变量,或者您的变量没有某些属性。如果您使用的是调试工具栏,则只需在“模板”部分检查上下文,或者,如果不够用的话,可以在填充完上下文后在视图代码中设置一个中断。

这样吧。


少打字只用import pudb;pu.db
斯瓦沃米尔Lenart

6

我强烈建议使用epdb(扩展的Python调试器)。

https://bitbucket.org/dugan/epdb

我喜欢epdb用于调试Django或其他Python网络服务器的一件事是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 help的更多信息。

如果要同时服务或连接到多个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())做与已接受答案相同的操作,但是由于我发现它非常有用,因此我想强调它的服务功能。


自2011年以来未更新epdb。在更新版本的Django和/或Python中使用它时是否遇到问题?
Seperman 2014年

我从未遇到针对Python 2(特别是2.4-2.7)使用它的问题。实际上,我几天前才使用它。我从来没有与Python 3尝试
Jacinda

1
我在python 2.7上运行django 1.8,但无法让epdb.connect与epdb.serve对话。我刚超时。
大卫·沃森

6

我刚刚找到wdb(http://www.rkblog.rk.edu.pl/w/p/debugging-python-code-browser-wdb-debugger/?goback=%2Egde_25827_member_255996401)。它有一个非常漂亮的用户界面/ GUI,带有所有的提示。作者说了有关wdb的内容-

“有些像PyCharm这样的IDE都有自己的调试器。它们提供相似或相同的功能集...但是,要使用它们,您必须使用那些特定的IDE(其中有些是非免费的,或者可能不适用于所有平台)。根据您的需求选择合适的工具。”

以为我会继续下去。

也是有关python调试器的非常有用的文章: https : //zapier.com/engineering/debugging-python-boss/

最后,如果您想在Django中看到调用堆栈的漂亮图形输出,请结帐:https : //github.com/joerick/pyinstrument。只需将pyinstrument.middleware.ProfilerMiddleware添加到MIDDLEWARE_CLASSES,然后在请求URL的末尾添加?profile即可激活分析器。

也可以从命令行或作为模块导入来运行pyinstrument。


我认为PyCharm仅使用PyDev,而不是自己的。
罗伯·格兰特

6

在Python代码的相应行中添加import pdb; pdb.set_trace()breakpoint() (形成python3.7)并执行它。执行将以交互式外壳程序停止。在外壳程序中,您可以执行Python代码(即打印变量)或使用以下命令:

  • c 继续执行
  • n 跳到同一功能的下一行
  • s 转到此函数或被调用函数的下一行
  • q 退出调试器/执行

另请参阅:https : //poweruser.blog/setting-a-breakpoint-in-python-438e23fe6b28


5

调试Django代码的最佳选择之一是通过wdb:https : //github.com/Kozea/wdb

wdb可与python 2(2.6、2.7),python 3(3.2、3.3、3.4、3.5)和pypy一起使用。甚至更好的是,可以用在python 3上运行的wdb服务器来调试python 2程序,反之亦然,或者用在第三台计算机的网页内的另一台计算机上运行的调试服务器来调试在计算机上运行的程序!更好的是,现在可以使用Web界面中的代码注入来暂停当前正在运行的python进程/线程。(这需要启用gdb和ptrace)换句话说,它是pdb的非常增强的版本,直接在浏览器中具有不错的功能。

安装并运行服务器,并在代码中添加:

import wdb
wdb.set_trace()

根据作者的说法,主要区别在于pdb

对于那些不了解项目的人,wdb是像pdb这样的python调试器,但是具有光滑的Web前端和许多其他功能,例如:

  • 源语法突出显示
  • 视觉断点
  • 使用jedi的交互式代码完成
  • 持久断点
  • 使用鼠标多线程/多处理支持进行深层对象检查
  • 远程调试
  • 观看表情
  • 在调试器代码版中
  • 流行的Web服务器集成可打破错误
  • 例如,在跟踪过程中发生异常中断(不是事后检验),与werkzeug调试器相反
  • 通过代码注入(在受支持的系统上)破坏当前正在运行的程序

它具有基于浏览器的出色用户界面。使用愉快!:)


与pdb有什么区别?
Dunatotatos



2

提到大多数选项。为了打印模板上下文,我为此创建了一个简单的库。参见https://github.com/edoburu/django-debugtools

您可以使用它来打印模板上下文,而无需任何{% load %}构造:

{% print var %}   prints variable
{% print %}       prints all

它使用定制的pprint格式在<pre>标签中显示变量。


2

我发现Visual Studio Code非常适合调试Django应用。标准的python launch.json参数python manage.py与附加的调试器一起运行,因此您可以根据需要设置断点并逐步执行代码。


2

对于那些可能意外将pdb添加到实时提交中的人,我可以建议#Koobz答案的扩展名:

@register.filter 
def pdb(element):
    from django.conf import settings
    if settings.DEBUG:    
        import pdb
        pdb.set_trace()
    return element

2

根据我自己的经验,有两种方法:

  1. 使用ipdb,它是像pdb一样的增强调试器。

    import ipdb;ipdb.set_trace()breakpoint() (来自python3.7)

  2. 使用django shell,只需使用下面的命令。在开发新视图时,这非常有帮助。

    python manage.py shell



1

如此处其他文章所述-在代码中设置断点并遍历代码以查看其行为是否符合您的预期,这是学习Django之类的好方法,直到您对所有行为的方式有了很好的了解-以及代码的含义是在做。

为此,我建议使用WingIde。就像其他提到的IDE一样,它们易于使用,易于布局,易于设置断点,可以评估/修改堆栈等。非常适合可视化代码在逐步执行时的工作。我是它的忠实粉丝。

我也使用PyCharm-它具有出色的静态代码分析功能,有时可以帮助您在发现问题之前就发现问题。

如前所述,django-debug-toolbar是必不可少的-https: //github.com/django-debug-toolbar/django-debug-toolbar

尽管不是明确的调试或分析工具,但我最喜欢的工具之一是可从Django Snippets获得的SQL Printing Middleware网址https://djangosnippets.org/snippets/290/

这将显示您的视图已生成的SQL查询。这将使您对ORM的工作以及查询是否有效还是需要重新编写代码(或添加缓存)有一个很好的了解。

我发现它在开发和调试应用程序时密切关注查询性能非常有用。

另一个提示-我稍作修改,只为显示摘要而不显示SQL语句...。因此,在开发和测试时我总是使用它。我还补充说,如果len(connection.queries)大于预定义的阈值,它将显示一个额外的警告。

然后,如果发现不良情况(从性能或查询数量的角度来看),我将重新打开SQL语句的完整显示以查看发生了什么。当您与多个开发人员一起从事大型Django项目时,非常方便。


1

使用pdbipdb。两者之间的区别在于ipdb支持自动完成。

对于pdb

import pdb
pdb.set_trace()

对于ipdb

import ipdb
ipdb.set_trace()

执行换行n击键,继续c击键。通过使用检查更多选项help(pdb)


0

另一个建议。

您可以一起使用鼻子测试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来查看模板中抱怨的脆性表单吗?

我可以。在鼻子测试中使用--pdb选项:

tests$ 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)         

现在,很明显,我对crispyfield构造函数的选择参数是因为它是列表中的列表,而不是元组的列表/元组。

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

整洁的是,此pdb发生在crispy的代码中,而不是我的,并且我不需要手动插入它。


0

在开发过程中,快速添加

assert False, value

可以帮助诊断视图中或其他任何地方的问题,而无需使用调试器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.