如何在Django中排除故障?
我之前是做PHP的,现在想学Python,但在调试方面遇到了很多困难,因为我还不太清楚在Django或者Python中该怎么做。
在PHP中,我习惯用print_r
或者var_dump
来查看所有东西。我可以在控制器、服务层或者模型中使用这些命令,然后数据就会在我的网页浏览器中显示出来。
但在Django中,我不能这样做。根据我正在做的事情,如果我在视图中尝试对一个对象使用print
,可能会导致页面崩溃,或者在控制台输出一些根本没用的信息。举个例子:
class Page(View):
def get(self, request, *args, **kwargs):
response = Data.objects.all()
# for whatever reason, I want to print something right now:
print response
# return JsonResponse({'success':response})
上面的代码会让我的页面完全崩溃,并显示一个提示:
The view didn't return an HttpResponse object. It returned None instead.
在使用CBV(类视图)时,我发现有些情况下可以把数据输出到控制台,但这些信息对我并没有帮助。例如,如果我想查看上面response
的内容,它会这样显示:
[object Object] [object Object] [object Object]
如果用var_dump
,我就能真正看到里面的内容。
所以我在想,我是不是做错了。人们在Python中调试时都是怎么输出数据的呢?如果有,他们是怎么做的,输出会显示在网页浏览器还是控制台?如果不是,那我该怎么在Django中处理基本的故障排除呢?以下是一些例子场景:
- 我想查看一个列表或字典的内容
- 我想查看ORM执行的原始SQL查询
- 我想确认一个函数是否被执行,可以在前端输出一些文本来查看
3 个回答
首先,Django 的视图需要返回某种 HttpResponse 对象。根据文档的说明——与 Django 自动创建的 HttpRequest 对象不同,HttpResponse 对象是你自己负责的。你写的每个视图都需要负责创建、填充和返回一个 HttpResponse。
你可以使用很多类来返回这个响应,比如 render_to_response、HttpResponseRedirect、JsonResponse 等等,还有很多其他的类——https://docs.djangoproject.com/en/dev/ref/request-response/#httpresponse-subclasses。你的代码行 # return JsonResponse({'success':response}) 如果去掉 # 就可以实现这个功能。
如果你想查看对象的内容,可以用 Python 的 dir 函数。这个函数会显示一个类或类实例的所有属性。可以参考——有没有函数可以打印 Python 对象的所有当前属性和数值?
你可以打印一个字典。有很多方法可以做到这一点。
for key,value in your_dictionary.items(): print(key, ":", value)
这很简单。你可以用 print Data.objects.all().query 来查看。可以参考——如何显示 Django 正在运行的 SQL
- 或者你可以在函数内部添加打印语句(或者使用一个装饰器来表明函数正在执行)。
这些都是 Django 和 Python 的基本部分。不是想冒犯你,但你可能更应该花时间去做一些完整的教程,而不是自己开始项目。一旦你理解了这些,事情就会变得很简单。MVC/MVT 框架的结构和 PHP 不一样,你需要适应这种工作方式,否则会感到沮丧。
首先,你遇到错误的原因不是因为你在打印,而是因为你把返回值注释掉了:
class Page(View):
def get(self, request, *args, **kwargs):
response = Data.objects.all()
# for whatever reason, I want to print something right now:
print response
return JsonResponse({'success':response}) # <-- dont comment this out
其次,打印一些随便的对象不一定能提供最有用的信息。如果一个对象定义了 __str__
或 __unicode__
方法,那么打印出来的就是这个方法的内容。否则,打印出来的就是对象的名字和它在内存中的地址,这样的信息并不太有用。打印一个对象并不会深入显示它的所有内容。
你可以尝试打印本地变量和全局变量:
print(locals())
print(globals())
或者把一个对象转换成 JSON 格式再打印出来:
print(json.dumps(response)) # some objects may not be serialisable to JSON though.
不过这样你可能也得不到想要的详细信息。另一种方法是把你的网络服务器运行在调试模式下,并抛出一个异常:
# settings.py
DEBUG = True
# views.py
def my_view(request):
raise Exception('debug')
这样就可以依靠 Django 显示调试错误页面,里面包含了堆栈跟踪信息,让你可以查看每一帧中所有可用的变量。
基本问题是,你习惯了PHP在请求/响应链中的工作方式,而Python在开发网页应用时的配置则有所不同。
在PHP的世界里,服务器会保证返回一个响应,这样就完成了请求/响应的循环。浏览器直接请求PHP文件,所以你并不知道后台实际上发生了什么。
一个典型的PHP请求,就像请求其他静态资源一样,比如一个普通的index.html
文件或logo.gif
。浏览器发出请求,网络服务器接受请求,然后返回响应;唯一的区别是如果请求的是一个.php
文件,它会经过一个中间步骤,PHP解释器会处理这个文件,然后把结果发回给客户端。
而在Python中,当请求映射到一个Python后台进程(有时称为上游进程)时,网络服务器会等待这个进程的响应(这个等待时间可以调整)。如果在规定的时间内没有收到响应,网络服务器就会发送一个超时错误页面(504错误)。
发送正确的响应(包括所有头信息等)是Python进程的责任,浏览器对此有一定的期望。在PHP中,这些细节对你(作为开发者)是隐藏的,因为PHP引擎会为你添加这些额外的信息。所以当你的Python代码没有发送这样的响应时(就像你遇到的情况),django会通过打印一个友好的错误信息来帮助你。
在你的情况下,视图没有返回响应;它只是打印了一些东西。这个打印语句会输出到应用程序的标准输出(或错误流),如果你在终端启动它,它会显示在控制台上,或者写入服务器的日志等,但不会发送回客户端(浏览器)。
为了调试django应用:
- 确保在你的
settings.py
中设置了DEBUG = True
- 用
python manage.py runserver
运行你的应用
现在,当你执行任何打印语句时,它会显示在控制台上,如果你的应用代码中有错误,只要你返回了有效的响应,你就会看到一个详细的错误页面和堆栈跟踪,帮助你找到问题。
在开发过程中,不再有“调试语句和在浏览器上打印东西”的情况;这就是Python在网络世界中的工作方式。
关于你的其他问题:
我想查看一个列表或字典的内容
直接打印它。输出会在你的控制台上(就是你输入
python manage.py runserver
的地方)我想查看ORM执行的原始SQL查询
如果你在django shell中测试,可以在ORM调用的末尾加上
.query
来查看发送的查询:>>> result = MyModel.objects.filter(foo='bar') >>> result.query (query printed here)
为了获得更丰富的调试体验,可以安装
django_debug_toolbar
。我想通过在前端输出一些文本来查看一个函数是否被执行
没有“输出到前端”的说法。对于这种情况,你可以直接
print()
你需要的内容,或者更好的是使用日志系统。