2010-03-18 8 views
7

Tôi đã viết chế độ xem Django nhỏ này để trả về pdf.Câu hỏi Django và Reportlab

@login_required 
def code_view(request,myid): 
    try: 
     deal = Deal.objects.get(id=myid) 
    except: 
     raise Http404 
    header = deal.header 
    code = deal.code 
    response = HttpResponse(mimetype='application/pdf') 
    response['Content-Disposition'] = 'attachment; filename=code.pdf' 
    p = canvas.Canvas(response) 
    p.drawString(10, 800, header) 
    p.drawString(10, 700, code) 
    p.showPage() 
    p.save() 
    return response 

Và câu hỏi của tôi:

  • tự UTF-8 không được hiển thị một cách chính xác trong pdf.
  • Tôi có thể bao gồm hình ảnh bằng cách nào?
  • Tôi có thể bao gồm một html rất cơ bản như:

.

<ul> 
    <li>List One</li> 
    <li>List Two</li> 
    <li>List Three</li> 
</ul> 

Trả lời

2

ReportLab có thể xử lý một số định dạng cơ bản HTML (<b>, <i>), không chắc chắn nếu nó có thể làm danh sách. Bạn có thể sử dụng pisa để chuyển đổi HTML sang PDF. Sau đó, bạn cũng có thể sử dụng thẻ <img> để bao gồm hình ảnh (Bạn cần phải cài đặt PIL để sử dụng hình ảnh)

10

Bạn nên chuyển sang cấp độ tiếp theo và sử dụng DocTemplates. Hình ảnh khá dễ dàng, nhưng việc sử dụng đạn thật sự rất khó - bạn phải xác định kiểu dáng và hơn thế nữa!

tôi sử dụng một tập các lớp như sau:

# -*- coding: utf-8 -*- 

from django.utils.encoding import smart_str 
from reportlab.lib.colors import Color 
from reportlab.lib.pagesizes import A4 
from reportlab.lib.styles import StyleSheet1, ParagraphStyle 
from reportlab.lib.units import cm 
from reportlab.pdfgen import canvas 
from reportlab.platypus.doctemplate import BaseDocTemplate, PageTemplate, \ 
    _doNothing 
from reportlab.platypus.frames import Frame 
from reportlab.platypus.paragraph import Paragraph 
import copy 
import re 
from reportlab.platypus.flowables import KeepTogether, Image, PageBreak 
from htmlentitydefs import name2codepoint 
from atom.http_core import HttpResponse 
import tempfile 

def htmlentitydecode(s): 
    return re.sub('&(%s);' % '|'.join(name2codepoint), lambda m: smart_str(unichr(name2codepoint[m.group(1)])), s) 

PS = ParagraphStyle 
stylesheet = StyleSheet1() 

stylesheet.add(PS(name='Normal', 
        leading=15)) 
stylesheet.add(PS(name='Bullet', 
        parent=stylesheet['Normal'], 
        bulletFontName = 'Symbol', 
        bulletIndent = 0, 
        bulletFontSize = 13, 
        bulletColor = Color(0.93,0,0), 
        bulletOffsetY = -1.5, 
        leftIndent = 15.8, 
        firstLineIndent = 0, 
       ), alias='bu') 
stylesheet.add(PS(name='Heading1', 
        parent=stylesheet['Normal'], 
        fontSize=18, 
        spaceAfter=23.5), alias='h1') 
stylesheet.add(PS(name='Heading2', 
        parent=stylesheet['Normal'], 
        fontSize=14, 
        spaceAfter=4), alias='h2') 
stylesheet.add(PS(name='Heading3', 
        parent=stylesheet['Normal'], 
        textColor=Color(0.93,0,0) 
       ), alias='h3') 
stylesheet.add(PS(name='Heading4', 
        parent=stylesheet['Heading3'], 
        textColor='black'), alias='h4') 

BulletStyle = copy.deepcopy(stylesheet["Bullet"]) 
H1Style = copy.deepcopy(stylesheet["Heading1"]) 
H2Style = copy.deepcopy(stylesheet["Heading2"]) 
H3Style = copy.deepcopy(stylesheet["Heading3"]) 
H4Style = copy.deepcopy(stylesheet["Heading4"]) 
NormalStyle = copy.deepcopy(stylesheet["Normal"]) 

top_margin = A4[1] - 1.22*cm 
bottom_margin = 1.5*cm 
left_margin = 2.8*cm 
frame_width = 17.02*cm 

right_margin = left_margin + frame_width 
frame_height = 22.7*cm 

letter_top_margin = 25.0*cm 
letter_bottom_margin = 3.0*cm 
letter_left_margin = 2.5*cm 
letter_right_margin = A4[0] - 2.5*cm 
letter_frame_width = A4[0] - 5.0*cm 
letter_frame_height = letter_top_margin - letter_bottom_margin 


class LetterTemplate(BaseDocTemplate): 
    _invalidInitArgs = ('pageTemplates',) 

    def handle_pageBegin(self): 
     self._handle_pageBegin() 
     self._handle_nextPageTemplate('First') 

    def build(self, flowables, onFirstPage=_doNothing, canvasmaker=canvas.Canvas): 
     self._calc() 

     frameT = Frame(letter_left_margin, letter_bottom_margin, letter_frame_width, letter_frame_height, 
         leftPadding=0, bottomPadding=0, rightPadding=0, topPadding=0, 
         id='normal') 

     self.addPageTemplates([PageTemplate(id='First',frames=frameT, onPage=onFirstPage, pagesize=self.pagesize)]) 

     if onFirstPage is _doNothing and hasattr(self,'onFirstPage'): 
      self.pageTemplates[0].beforeDrawPage = self.onFirstPage 

     BaseDocTemplate.build(self, flowables, canvasmaker=canvasmaker) 


class PdfA4Letter(object): 

    def __init__(self, filename): 
     self.title = filename 
     self._keep_together = False 
     self.elements = [] 
     self._keep_together_elements = [] 
     self.doc = LetterTemplate(filename,showBoundary=False) 
     self.elements = [] 

    def _process_text(self, txt): 
     text_elems = [] 

     # avoid us from user added html. 
     txt = txt.replace('&lt;','&lang;').replace('&gt;','&rang;') 
     txt = htmlentitydecode(smart_str(txt).replace('<p>', '').replace('</p>', '<br />')) 

     # @todo: in some case the reegxp does not work -> hack 
     txt = txt.replace('target="_blank"', '') 
     # process text 
     for part in re.split('<ul>|</ul>|<ol>|</ol>', txt): 
      part = part.strip() 
      if part.count('<li>') > 0: 
       for item in re.split('<li>|</li>', part): 
        item = item.strip() 
        if len(item) > 0: 
         text_elems.append(Paragraph(item, BulletStyle, bulletText=u'•')) 
      else: 
       text_elems.append(Paragraph(part, NormalStyle)) 
     return text_elems 

    def _store_flowable(self, flowable):   
     if self._keep_together == False: 
      self.elements.append(flowable) 
     else: 
      self._keep_together_elements.append(flowable) 

    def start_keep_together(self): 
     self.end_keep_together() 
     self._keep_together = True 

    def end_keep_together(self): 
     self._keep_together = False 
     if len(self._keep_together_elements) > 0: 
      e = self._keep_together_elements 
      self.elements.append(KeepTogether(e)) 
      self._keep_together_elements = [] 

    def newPage(self): 
     self._store_flowable(PageBreak()) 

    def blankline(self, cnt=1): 
     self.text(cnt*'<br/>') 

    def text(self, txt): 
     for e in self._process_text(txt): 
      self._store_flowable(e)   

    def image(self, name, width, height, halign='CENTER'): 
     im = Image(name, width=width, height=height) 
     im.hAlign = halign 
     self._store_flowable(im) 

    def h1(self, txt, add_to_toc=True): 
     self.newPage() 
     self._store_flowable(Paragraph(txt, H1Style)) 

    def h2(self, txt, add_to_toc=True): 
     self._store_flowable(Paragraph(txt, H2Style)) 

    def h3(self, txt, add_to_toc=False): 
     self._store_flowable(Paragraph(txt, H3Style)) 

    def h4(self, txt, add_to_toc=False): 
     self._store_flowable(Paragraph(txt, H4Style)) 

    def _drawPage(self, canvas, doc): 
     canvas.setSubject('Letter Subject') 
     canvas.setTitle('Letter Title') 
     canvas.setAuthor('Me') 

    def build(self): 
     # flush elems 
     self.end_keep_together() 
     self.doc.build(self.elements, self._drawPage) 

Sau đó, bạn có thể xử lý thế hệ pdf theo quan điểm của bạn, như thế này:

def view(request): 

    file = tempfile.NamedTemporaryFile() 

    e = PdfA4Letter(file.name) 

    ref = '/absolute/path/to/image.png' 
    e.image(ref, width=frame_width, height=10*cm) 
    e.h1((u'Über Mich')) 
    e.h3('Next header') 

    t = """ 
    ascasc<br /> 
    ascascasc<br /> 
    <ul> 
     <li>sdv1</li> 
     <li>sdv2</li> 
     <li>sdv3</li> 
    </ul> 
    ascasc<br /> 
    ascasc<br /> 
    """ 

    e.text(t) 
    e.blankline(2) 
    e.end_keep_together() 
    e.build() 

    response = HttpResponse(mimetype='application/pdf') 
    response['Content-Disposition'] = 'attachment; filename=gugus.pdf' 
    response.write(file.read()) 
    file.close() 
    return response