【问题标题】:Django produces blank pages when POST data is sent and Models are accessed发送 POST 数据并访问模型时,Django 会产生空白页
【发布时间】:2011-08-30 05:00:30
【问题描述】:

我正在为此拉头发。我正在 Django 1.3 中开发一个 webapp(最近从 1.2.5 升级,希望这可能会解决我的错误),我在我的一个观点中遇到了一个奇怪的错误。

视图被称为来自客户端的 AJAX 请求。如果我将视图称为 GET 请求,那么一切都很好。如果我将其称为没有数据的 POST 请求,那么一切都很好。但是,如果我将其称为 POST 并实际包含数据(无论该数据是什么),Django 会返回一个空白页。

作为一个善于修补的人,我发现我可以从我的视图中打印并在调试控制台中获取输出,所以我开始工作,并发现了这个奇怪的怪事:

c = Character.objects.get(id=int(character))

这是该视图中处理模型的第一行代码。打印显示不仅 character 是一个合理的值(它是请求传入的 ID),而且 c 实际上以正确的数据库记录结束。无论如何,如果调用该行,Django 的请求输出是 zilch。纳达。没有。

如果我在对模型做任何事情之前提前返回,Django 会正确呈现请求的其余部分。对模型执行某些操作会导致发送响应 200,但内容似乎被省略了。

这似乎只在发送 POST 数据时发生,无论是否以任何方式读取或使用该 POST 数据。我对此完全感到困惑。我将在这里发布我的代码,并希望这里的人对幕后可能发生的黑魔法有所了解。

这是视图本身,直接从 urls.py 调用:

@csrf_exempt
def ajax_update(request, character):
    #determine the timestamp to send the client *before* polling
    #the database

    update_time = int(time.time())

    #grab each update... thingy as json, and put it all together
    output = {
        "events": current_events(request, character, "default"),
        "character": character,
        "update_time": update_time,
    }

    return HttpResponse(json.dumps(output), mimetype = "application/json")

这是 current_events 代码,其中包含提到的行:

def current_events(request, character, type = "default", timestamp = 0):
    '''
    purpose: grab the last 3 days worth of events, or the last 10 events,
    whichever is a larger list.
    '''

    #TODO: actually do something with timestamp
    c = Character.objects.get(id=int(character))

    #DEBUG: What on earth is going on here?
    print c

    #TODO: See if this can be optimized into a single query
    event_links = EventLink.objects.filter(viewer=c)
    events = Event.objects.filter(id__in=event_links.values('event')).order_by('timestamp')

    t = loader.get_template('ajax/world-events.html')

    output = []

    for event in events:
        revisions = Event.objects.filter(original_event=event.id).order_by('timestamp')

        display_message = event.message

        history = []
        if len(revisions):
            history.append(event) #first item in the history is the original event
            history.extend(revisions)   
            display_message = history[-1].message

        output.append({
            "id": event.id,
            "writer": event.writer.id,
            "type": event.type,
            "timestamp": int(time.mktime(event.timestamp.timetuple())),
            "message": t.render(RequestContext(request, {"event_text": display_message, "event": event, "history": history}))
        })

    return output

最后,这是使用 jQuery 从客户端调用代码的 CoffeeScript:

auto_refresh_abort = 0
last_server_timestamp = 0
window.update_display = ->  
    #ajax call to grab events from the server
    $.ajax 
        type: 'POST'
        url: "/ajax/update/"+window.active_character
        data: 
            "last_update": last_server_timestamp
        dataType: "json"
        success: (output) ->
            auto_refresh_abort = 0
            update_character_log output.events
        error: (XMLHttpRequest, textStatus, errorThrown) ->
            auto_refresh_abort += 1
            console.log XMLHttpRequest

    return null

如果您认为它会有所帮助(这已经很多了),我可以发布任何其他需要的代码示例,例如模型代码本身。我可以确认在我的测试用例中正在查找的 Character 确实存在,而且它只是一个标准的 Django ID,我没有用它做任何奇怪的事情。

提前致谢。

更新:根据要求,以下是输出应包含的示例:

{'update_time': 1305984080, 'character': u'1', 'events': /*snip*/}

我已经验证代码执行一直在进行,并且传递给 HttpResponse 的输出确实包含这些数据。为了咯咯笑,我在我轮询字符的行之后插入了一个返回“TASTY”,所以输出的数据应该是:

{'update_time': 1305984080, 'character': u'1', 'events': 'TASTY'}

并确认这是有效的。我可以在 HttpRequest 之前将输出“打印”到调试控制台并显示出来。

如果我注释掉处理字符的行,我的浏览器会接收此数据作为请求的内容。此外,如果我保留代码原样并且根本不发送 POST 数据,则浏览器会收到正确的数据。它失败的具体情况是当我在从客户端发送 POST 数据后操作模型时——在这种情况下,浏览器接收到完全相同的 HTTP 标头,但没有内容。它收到的标头是:

Content-Type:application/json
Date:Sat, 21 May 2011 13:29:38 GMT
Server:WSGIServer/0.1 Python/2.6

但没有提供实际内容。

【问题讨论】:

  • 哦:我是 Django 新手,但在此之前它几乎没有痛苦。我也是……嗯,不是全新的,但对 Python 不是特别有经验,所以如果我的风格不完美,我深表歉意。我还在学习技巧。
  • 添加“import pdb; pdb.set_trace()”作为视图的第一行。这将在您的控制台中启动 pdb(调试器)。您可以使用 pdb 来检查您的对象并逐步进行。以这种方式跟踪问题比使用打印更容易。 :)
  • 这并不重要 - 但为什么你甚至不使用发布的数据时还要进行 POST?
  • 我完全打算使用发布的数据。在编写该代码之前,我只是碰巧发现了这个奇怪的错误。我先写了客户端代码。 POST 数据是客户端最近的时间戳,我将用它来省略它应该已经有的更改。
  • 叹息。我唯一想到的是,在 HttpResponse 有机会之前,其他东西正在发送 HTTP 标头。但这并没有多大意义,因为我的浏览器 正在 获取标头,并且它们具有我在 ajax_update 中设置的 application/json mimetype。只是……没有内容。我已经验证输出包含有效数据,并且 json.dumps(output) 正在生成有效数据。我只是不明白为什么 HttpResponse 似乎会吃掉它,以及为什么它只在操纵模型之后才会这样做。

标签: jquery python ajax django


【解决方案1】:

这将是一个答案。它是一种方法,因此您一开始就不会遇到此问题,但如果发生问题,您也可以使用它来调试问题。

  1. 首先使用 curl 或使用 firefox REST 客户端 plugin 创建您的请求:

  2. 然后您编写响应代码返回硬编码的虚拟对象响应,涵盖几个案例(或所有用例)。所以你的 character 和 current_events 函数只返回你知道是正确的“虚拟”对象。

  3. 您使用 REST 客户端(或更正式的测试)验证响应是否正常工作。

  4. 您编写客户端 ajax 代码并验证它是否适用于虚拟输出。

  5. 您将虚拟对象调用重构为调用对象本身的函数(您可以很快验证它们是否以应有的方式返回对象。

您可以使用它来有效地调试您的程序,否则,您只是在猜测程序的哪个部分在工作,它很容易在很多地方失败。

【讨论】:

  • 虽然这在实践中是个好主意,但我在这里遇到的具体问题不会得到解决。我已经确认一切都在使用虚拟对象——特别是你的第 5 步是我遇到问题的地方。数据库代码本身似乎是导致问题的原因。
  • 打印并检查它是否具有合理的值与使用虚拟对象不同。帖子中没有任何内容表明您使用了虚拟对象。粘贴一个 json.dumps(output) 应该是什么样子的例子,并粘贴一个你得到的例子。 (并确认您的代码适用于您期望的 json.dumps(output) 示例。
  • 就是这样——我正在恢复理智的对象。应该存在的确切输出是 there,HttpRequest 只是...吃掉它。我没有其他办法来解释它。输出正在正确生成。给它虚拟默认值没有帮助——我可以验证包含“虚拟”的计划字符串将作为“”发送到浏览器。如果有帮助,我会看看是否可以在我的代码之外重现确切的问题。
  • 并返回 HttpResponse(some_json_data, mimetype = "application/json") 也不起作用?在上面的段落中,您提到了提前“返回”,这是否还包括使用非模型 json 数据提前返回。如果是这样,请尝试使用 curl 或 rest-client 返回 text/html 响应的相同视图
  • ...好吧,更奇怪了。我打开 Firefox 试图找到这个插件,我正确解析的数据正盯着我看。好奇,我打开 IE9 得到的结果好坏参半,大约有四分之一的更新正确,其余的什么都不做。超级奇怪,但这是一个提示。标题明显有问题。我想知道这是否可能是开发服务器中的错误?我会尝试将它连接到 Apache 并查看是否可以修复它。我想一个更好的问题是 Django 的数据库模型框架是否响应 HTTP 标头——如果是,那可能正是它要向南发展的地方。
【解决方案2】:

我想我可能找到了我的问题。一旦我将我的应用程序连接到 Apache 并停止使用 Django 的开发服务器,这个奇怪的错误就消失了。现在总是会发送响应。

我仍然不知道原因是否是我自己的代码中的错误,或者这是否只是开发服务器的一个奇怪的怪癖,所以我发布这个答案是希望如果其他人遇到开发过程中出现类似错误,这可能会对主题有所启发。

似乎开发服务器对其所做的 HTTP 标头很挑剔,并且不喜欢接受 POST 数据。如果我能缩小问题的确切原因,以及在什么情况下,我会用更多的细节来编辑这个。对我来说,一个临时的解决方法是使用 Firefox 进行开发,Django 似乎喜欢它的标头。 Apache下的生产环境不受此bug影响。

【讨论】:

  • 感谢您的反馈。我的问题与您的问题非常相似,只有我可以在我的代码的某些部分而不是其他部分中获得对我的 POST 的响应。很奇怪。我在我的测试环境中使用了 nginx/uwsgi,但是当我转移到 Django 开发服务器时它开始工作了。至少现在我知道从哪里开始调试了。
  • 我在这个问题的帮助下找出了我的具体问题的问题:stackoverflow.com/questions/3970495/…。问题是没有读取 POST 数据。如果您在视图的开头放置 request.POST 来使用 POST 数据,它是否解决了您的问题?我必须在 uwsgi 中添加“--pep3333-input”--post-buffering 4096”参数来修复我的环境。
猜你喜欢
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多