1

出力データのダウンロード可能なバージョンを提供するために別の Web サービスで使用される、次の Django ビュー コードを継承しました。

def index(request):
    # ... (snip) ...
    data = base64.decodestring(request.POST['data'])
    filename = request.POST['filename']

    wrapper = FileWrapper(StringIO(data))

    response = HttpResponse(wrapper, content_type=guess_type(str(filename))[0])

    response['Content-Length'] = len(data)
    response['Content-Disposition'] = "attachment; filename=" + filename

    return response

Django 1.0 に対して書かれた関数自体は、1.5 にアップグレードした後も問題なく動作します。残念ながら、このビューをカバーするテストは現在失敗しています。

    def testDownload(self):
        self.client.login(username='test', password='test')

        real = 'abc' * 100
        data = base64.encodestring(real)
        response = self.client.post("/api/v1/download/", {'data': data, 'filename': 'out.jpg'})

        self.assertEqual(real, response.content)
        self.assertEqual(response['Content-Disposition'], 'attachment; filename=out.jpg')

そしてエラー:

Traceback (most recent call last):
  File "/home/fred/.secret_projects/final/gerbils/tests/amf.py", line 548, in testDownload
    self.assertEqual(real, response.content)
  File "/home/fred/.virtualenvs/cunning_plot/lib/python2.7/site-packages/django/http/response.py", line 282, in content
    self._consume_content()
  File "/home/carl/.virtualenvs/cunning_plot/lib/python2.7/site-packages/django/http/response.py", line 278, in _consume_content
    self.content = b''.join(self.make_bytes(e) for e in self._container)
  File "/home/carl/.virtualenvs/cunning_plot/lib/python2.7/site-packages/django/http/response.py", line 278, in <genexpr>
    self.content = b''.join(self.make_bytes(e) for e in self._container)
  File "/usr/lib64/python2.7/wsgiref/util.py", line 30, in next
    data = self.filelike.read(self.blksize)
  File "/usr/lib64/python2.7/StringIO.py", line 127, in read
    _complain_ifclosed(self.closed)
  File "/usr/lib64/python2.7/StringIO.py", line 40, in _complain_ifclosed
    raise ValueError, "I/O operation on closed file"
ValueError: I/O operation on closed file

それで..何かアイデアはありますか?読み取る必要がある前に、testDownload()またはindex()必然的に「閉じる」ものは何も表示されません。StringIOまた、何かあればテスト以外にも影響が出るのではないでしょうか?

非常に混乱。助けていただければ幸いです。

4

1 に答える 1

5

がどこで呼び出されているかを確認する簡単な方法closeは、サブクラスStringIO化し、close 関数にブレークポイントを配置することです。

class CustomStringIO(StringIO):
    def close(self):
        import pdb; pdb.set_trace()
        super(CustomStringIO, self).close()

このためのスタックは

-> response = self.client.post("/test/", {'data': data, 'filename': 'out.jpg'})
  ...\venv\lib\site-packages\django\test\client.py(463)post()
-> response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
  ...\venv\lib\site-packages\django\test\client.py(297)post()
-> return self.request(**r)
  ...\venv\lib\site-packages\django\test\client.py(406)request()
-> response = self.handler(environ)
  ...\venv\lib\site-packages\django\test\client.py(119)__call__()
-> response.close()                    # will fire request_finished
  ...\venv\lib\site-packages\django\http\response.py(233)close()
-> closable.close()
> \testapp\views.py(11)close()
-> super(CustomStringIO, self).close()

テスト クライアントが応答を閉じているように見えます。これにより、 close が呼び出されFileWrapper、次に close on が呼び出されStringIOます。これは、実際に に到達する前のすべてですresponse.content

必要な理由はありFileWrapperますか?HttpResponse文字列の内容を取り込んでバイナリ文字列を返すので、 andを作成する代わりに に直接base64.decodestring渡すことができるようです。dataHttpResponseStringIOFileWrapper

于 2013-10-15T18:32:40.977 に答える