2010-08-03 1 views
1

PDF로 보고서를 내보내는 webapp가 있습니다. 쿼리가 100 개 미만의 값을 반환하면 모든 것이 잘됩니다. 레코드 수가 100을 초과하면 서버는 502 프록시 오류를 발생시킵니다. 이 보고서는 HTML 형식으로 출력됩니다. 서버를 끊는 프로세스는 html에서 PDF 로의 변환입니다. xhtml2pdf (AKA pisa 3.0)을 사용하여 PDF를 생성하고 있습니다. 나는 서버가 일부 메모리를 확보 할 수 있습니다하지만 난 아직 아무것도 찾지 못했습니다 그래서 버퍼를 만드는 방법에 대한 몇 가지 생각을 넣었습니다Django/Python에서 PDF 변환 최적화

def view1(request, **someargs): 
    queryset = someModel.objects.get(someargs) 
    if request.GET['pdf']: 
     return pdfWrapper('template.html',queryset,'filename') 
    else: 
     return render_to_response('template.html',queryset) 

def pdfWrapper(template_src, context_dict, filename): 
    ################################################ 
    # 
    # The code comented below is an older version 
    # I updated the code according the comment recived 
    # The function still works for short HTML documents 
    # and produce the 502 for larger onese 
    # 
    ################################################ 

    ##import cStringIO as StringIO 
    import ho.pisa as pisa 
    from django.template.loader import get_template 
    from django.template import Context 
    from django.http import HttpResponse 
    ##from cgi import escape 

    template = get_template(template_src) 
    context = Context(context_dict) 
    html = template.render(context) 

    response = HttpResponse() 
    response['Content-Type'] ='application/pdf' 
    response['Content-Disposition']='attachment; filename=%s.pdf'%(filename) 

    pisa.CreatePDF(
     src=html, 
     dest=response, 
     show_error_as_pdf=True) 

    return response 

    ##result = StringIO.StringIO() 
    ##pdf = pisa.pisaDocument(
    ##   StringIO.StringIO(html.encode("ISO-8859-1")), 
    ##   result) 
    ##if not pdf.err: 
    ## response = HttpResponse(
    ##     result.getvalue(), 
    ##     mimetype='application/pdf') 
    ## response['Content-Disposition']='attachement; filename=%s.pdf'%(filename) 
    ## return response 
    ##return HttpResponse('Hubo un error<pre>%s</pre>' % escape(html)) 

다음 algorythm이 같은 것입니다. 누구든지 도움을 줄 수 있습니까? 부디?

+0

@ bernd-petersohn은 아래에 지적했듯이 cStringIO와 StringIO는 실제로 인터넷을 통해 콘텐츠를 스트리밍하지 않고 메모리에 상주하는 "파일과 유사한 객체"를 만들어 디스크에 꼭 필요하지는 않습니다. – marcoslhc

답변

3

문제를 일으키는 원인을 정확히 알 수는 없지만 StringIO의 버퍼링 문제로 인해 발생할 수 있습니다.

그러나이 코드가 실제로 생성 된 PDF 데이터를 스트리밍한다고 가정하면 잘못된 것입니다. StringIO.getvalue()는 출력 스트림이 아니라이 메서드가 호출 될 때 문자열 버퍼의 내용을 반환합니다 (http://docs.python.org/library/stringio.html#StringIO.StringIO.getvalue 참조).).

출력을 스트리밍하려는 경우 HttpResponse 인스턴스를 파일과 유사한 객체로 처리 할 수 ​​있습니다 (http://docs.djangoproject.com/en/1.2/ref/request-response/#usage 참조).

두 번째로 여기에서는 StringIO를 사용할 이유가 없습니다. 피사의 설명서에 따르면 (이 함수는 CreatePDF라고 부름) 소스는 문자열 또는 유니 코드 객체가 될 수 있습니다. 개인적으로

, 나는 시도 할 것이다 다음

  1. 를 HttpResponse에 개체
  2. 전화 입력으로 문자열 출력으로 응답과 PDF 생성을
  3. 만들기 유니 코드 문자열로 HTML을 생성 및 구성 개요에서

이는 다음과 같이 수 :

html = template.render(context) 

response = HttpResponse() 
response['Content-Type'] ='application/pdf' 
response['Content-Disposition']='attachment; filename=%s.pdf'%(filename) 

pisa.CreatePDF(
    src=html, 
    dest=response, 
    show_error_as_pdf=True) 

#response.flush() 
return response 

그러나 실제로는 이 아니고이 시도됩니다. (나는 지금까지 자바에서만 스트리밍하는 이런 종류의 일을했다.)

업데이트 : 나는 HttpResponse의 구현을 살펴 보았다. 목록에 기록 된 문자열 청크를 수집하여 파일 인터페이스를 구현합니다. response.flush()를 호출하면 아무 일도 일어나지 않기 때문에 무의미합니다. 또한 응답이 파일 객체로 액세스 된 후에도 Content-Type과 같은 응답 매개 변수를 설정할 수 있습니다.

원래 문제는 사용자가 결코 StringIO 개체를 닫지 않았다는 사실과 관련이있을 수 있습니다. StringIO 객체의 기본 버퍼는 close()가 호출되기 전에 해제되지 않습니다.

+0

Yeap, I close() 호출에 대해 생각했다. 나는 당신의 제안을 시도하고 알려 드리겠습니다. 이 문제에 대한 노력에 감사드립니다! – marcoslhc

+0

나는 당신의 제안을 받아 CreatePDF() 함수를 사용하고 모든 StringIO 물건을 버린다. 더 깨끗하고 단순한 솔루션입니다. 그러나 여전히 나타나는 502. 지금은 더 나은 메모리 관리를 할 수 있는지 디스크에 파일을 쓰려고합니다. – marcoslhc

+0

피사 소스를 통해 조금 탐색했을 때 원래 코드가 이미 제시된 예제에 매우 근접한 것으로 나타났습니다. 그래서 내 생각 엔 피사의 PDF 생성 기능에서 실제 문제가 더 많다는 것입니다. 버그 보고서 (http://code.google.com/p/xhtml2pdf/issues/detail?id=50)는 실제 PDF가 끝나기 전에 생성기가 너무 일찍 돌아 오는 경우가 있음을 나타냅니다. 이 문제가 귀하의 경우에도 발생하면 502 오류 응답의 원인이 될 수 있습니다. 위에서 제안한대로 파일에 PDF 출력을 쓰면이 문제를 해결할 수 있습니다. –