Python Reportlab 划分 table 以适应不同的页面
Python Reportlab divide table to fit into different pages
我正在尝试在使用 ReportLab 生成的 PDF 文件中构建进度计划器。根据一天中的不同时间,时间表将有不同的行:从 8:00 a.m., 8:15 a.m., 8:30 a.m 开始].,等等.
我做了一个循环,在这个循环中会自动计算小时数并填写时间表。但是,由于我的 table 太长,无法完全放入页面中。 (虽然时间表应该在 7:30 p.m. 结束,但它在 2:00 p.m. 被剪掉了。)
期望的结果是在 table 大约有 20 个活动时有一个 PageBreak。在下一页中,header 应该与第一页及下面完全相同,是 table 的延续。每次有必要时都应重复该过程,直到 table.
结束
Python代码如下:
from reportlab.pdfgen.canvas import Canvas
from datetime import datetime, timedelta
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, landscape
class Vendedor:
"""
Información del Vendedor: Nombre, sucursal, meta de venta
"""
def __init__(self, nombre_vendedor, sucursal, dia_reporte):
self.nombre_vendedor = nombre_vendedor
self.sucursal = sucursal
self.dia_reporte = dia_reporte
class Actividades:
"""
Información de las Actividades realizadas: Hora de actividad y duración, cliente atendido,
tipo de actividad, resultado, monto venta (mxn) + (usd), monto cotización (mxn) + (usd),
solicitud de apoyo y comentarios adicionales
"""
def __init__(self, hora_actividad, duracion_actividad, cliente, tipo_actividad, resultado,
monto_venta_mxn, monto_venta_usd, monto_cot_mxn, monto_cot_usd, requiero_apoyo, comentarios_extra):
self.hora_actividad = hora_actividad
self.duracion_actividad = duracion_actividad
self.cliente = cliente
self.tipo_actividad = tipo_actividad
self.resultado = resultado
self.monto_venta_mxn = monto_venta_mxn
self.monto_venta_usd = monto_venta_usd
self.monto_cot_mxn = monto_cot_mxn
self.monto_cot_usd = monto_cot_usd
self.requiero_apoyo = requiero_apoyo
self.comentarios_extra = comentarios_extra
class PDFReport:
"""
Crea el Reporte de Actividades diarias en archivo de formato PDF
"""
def __init__(self, filename):
self.filename = filename
vendedor = Vendedor('John Doe', 'Stack Overflow', datetime.now().strftime('%d/%m/%Y'))
file_name = 'cronograma_actividades.pdf'
document_title = 'Cronograma Diario de Actividades'
title = 'Cronograma Diario de Actividades'
nombre_colaborador = vendedor.nombre_vendedor
sucursal_colaborador = vendedor.sucursal
fecha_actual = vendedor.dia_reporte
canvas = Canvas(file_name)
canvas.setPageSize(landscape(letter))
canvas.setTitle(document_title)
canvas.setFont("Helvetica-Bold", 20)
canvas.drawCentredString(385+100, 805-250, title)
canvas.setFont("Helvetica", 16)
canvas.drawCentredString(385+100, 785-250, nombre_colaborador + ' - ' + sucursal_colaborador)
canvas.setFont("Helvetica", 14)
canvas.drawCentredString(385+100, 765-250, fecha_actual)
title_background = colors.fidblue
hour = 8
minute = 0
hour_list = []
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
i = 0
for i in range(47):
if minute == 0:
if hour <= 12:
time = str(hour) + ':' + str(minute) + '0 a.m.'
else:
time = str(hour-12) + ':' + str(minute) + '0 p.m.'
else:
if hour <= 12:
time = str(hour) + ':' + str(minute) + ' a.m.'
else:
time = str(hour-12) + ':' + str(minute) + ' p.m.'
if minute != 45:
minute += 15
else:
hour += 1
minute = 0
hour_list.append(time)
# I TRIED THIS SOLUTION BUT THIS DIDN'T WORK
# if i % 20 == 0:
# canvas.showPage()
data_actividades.append([hour_list[i], i, i, i, i, i, i, i])
i += 1
table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)
tblStyle = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), title_background),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (1, 0), (1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
rowNumb = len(data_actividades)
for row in range(1, rowNumb):
if row % 2 == 0:
table_background = colors.lightblue
else:
table_background = colors.aliceblue
tblStyle.add('BACKGROUND', (0, row), (-1, row), table_background)
table_actividades.setStyle(tblStyle)
width = 150
height = 150
table_actividades.wrapOn(canvas, width, height)
table_actividades.drawOn(canvas, 65, (0 - height) - 240)
canvas.save()
我尝试添加:
if i % 20 == 0:
canvas.showPage()
然而这并没有达到预期的效果。
其他快速说明:尽管我专门对 table 的列标题进行了编码。一旦我 运行 程序,列标题的顺序由于某种原因被修改(参见粘贴的图像)。知道为什么会这样吗?
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
非常感谢您,祝您愉快!
您应该按照官方文档第 5 章“PLATYPUS - 页面布局和排版使用脚本”中的建议使用模板。
基本思想是使用框架,并将要添加的所有信息添加到列表元素中。在我的例子中,我称之为“内容”,使用命令“contents.append(FrameBreak())
”你离开框架并在下一个框架上工作,另一方面,如果你想改变模板的类型,你使用命令“
contents.append(NextPageTemplate('<template_name>'))
"
我的建议:
对于你的情况,我使用了两个模板,第一个是包含带有 sheet 信息的 header 和 table 的第一部分的模板,另一个是模板对应于其余内容。这些模板的名称是firstpage,laterpage.The代码如下:
from reportlab.pdfgen.canvas import Canvas
from datetime import datetime, timedelta
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, landscape
from reportlab.platypus import BaseDocTemplate, Frame, Paragraph, PageBreak, \
PageTemplate, Spacer, FrameBreak, NextPageTemplate, Image
from reportlab.lib.pagesizes import letter,A4
from reportlab.lib.units import inch, cm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER,TA_LEFT,TA_RIGHT
class Vendedor:
"""
Información del Vendedor: Nombre, sucursal, meta de venta
"""
def __init__(self, nombre_vendedor, sucursal, dia_reporte):
self.nombre_vendedor = nombre_vendedor
self.sucursal = sucursal
self.dia_reporte = dia_reporte
class Actividades:
"""
Información de las Actividades realizadas: Hora de actividad y duración, cliente atendido,
tipo de actividad, resultado, monto venta (mxn) + (usd), monto cotización (mxn) + (usd),
solicitud de apoyo y comentarios adicionales
"""
def __init__(self, hora_actividad, duracion_actividad, cliente, tipo_actividad, resultado,
monto_venta_mxn, monto_venta_usd, monto_cot_mxn, monto_cot_usd, requiero_apoyo, comentarios_extra):
self.hora_actividad = hora_actividad
self.duracion_actividad = duracion_actividad
self.cliente = cliente
self.tipo_actividad = tipo_actividad
self.resultado = resultado
self.monto_venta_mxn = monto_venta_mxn
self.monto_venta_usd = monto_venta_usd
self.monto_cot_mxn = monto_cot_mxn
self.monto_cot_usd = monto_cot_usd
self.requiero_apoyo = requiero_apoyo
self.comentarios_extra = comentarios_extra
class PDFReport:
"""
Crea el Reporte de Actividades diarias en archivo de formato PDF
"""
def __init__(self, filename):
self.filename = filename
vendedor = Vendedor('John Doe', 'Stack Overflow', datetime.now().strftime('%d/%m/%Y'))
file_name = 'cronograma_actividades.pdf'
document_title = 'Cronograma Diario de Actividades'
title = 'Cronograma Diario de Actividades'
nombre_colaborador = vendedor.nombre_vendedor
sucursal_colaborador = vendedor.sucursal
fecha_actual = vendedor.dia_reporte
canvas = Canvas(file_name, pagesize=landscape(letter))
doc = BaseDocTemplate(file_name)
contents =[]
width,height = A4
left_header_frame = Frame(
0.2*inch,
height-1.2*inch,
2*inch,
1*inch
)
right_header_frame = Frame(
2.2*inch,
height-1.2*inch,
width-2.5*inch,
1*inch,id='normal'
)
frame_later = Frame(
0.2*inch,
0.6*inch,
(width-0.6*inch)+0.17*inch,
height-1*inch,
leftPadding = 0,
topPadding=0,
showBoundary = 1,
id='col'
)
frame_table= Frame(
0.2*inch,
0.7*inch,
(width-0.6*inch)+0.17*inch,
height-2*inch,
leftPadding = 0,
topPadding=0,
showBoundary = 1,
id='col'
)
laterpages = PageTemplate(id='laterpages',frames=[frame_later])
firstpage = PageTemplate(id='firstpage',frames=[left_header_frame, right_header_frame,frame_table],)
contents.append(NextPageTemplate('firstpage'))
logoleft = Image('logo_power.png')
logoleft._restrictSize(1.5*inch, 1.5*inch)
logoleft.hAlign = 'CENTER'
logoleft.vAlign = 'CENTER'
contents.append(logoleft)
contents.append(FrameBreak())
styleSheet = getSampleStyleSheet()
style_title = styleSheet['Heading1']
style_title.fontSize = 20
style_title.fontName = 'Helvetica-Bold'
style_title.alignment=TA_CENTER
style_data = styleSheet['Normal']
style_data.fontSize = 16
style_data.fontName = 'Helvetica'
style_data.alignment=TA_CENTER
style_date = styleSheet['Normal']
style_date.fontSize = 14
style_date.fontName = 'Helvetica'
style_date.alignment=TA_CENTER
canvas.setTitle(document_title)
contents.append(Paragraph(title, style_title))
contents.append(Paragraph(nombre_colaborador + ' - ' + sucursal_colaborador, style_data))
contents.append(Paragraph(fecha_actual, style_date))
contents.append(FrameBreak())
title_background = colors.fidblue
hour = 8
minute = 0
hour_list = []
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
i = 0
for i in range(300):
if minute == 0:
if hour <= 12:
time = str(hour) + ':' + str(minute) + '0 a.m.'
else:
time = str(hour-12) + ':' + str(minute) + '0 p.m.'
else:
if hour <= 12:
time = str(hour) + ':' + str(minute) + ' a.m.'
else:
time = str(hour-12) + ':' + str(minute) + ' p.m.'
if minute != 45:
minute += 15
else:
hour += 1
minute = 0
hour_list.append(time)
# I TRIED THIS SOLUTION BUT THIS DIDN'T WORK
# if i % 20 == 0:
data_actividades.append([hour_list[i], i, i, i, i, i, i, i])
i += 1
table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)
tblStyle = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), title_background),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (1, 0), (1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
rowNumb = len(data_actividades)
for row in range(1, rowNumb):
if row % 2 == 0:
table_background = colors.lightblue
else:
table_background = colors.aliceblue
tblStyle.add('BACKGROUND', (0, row), (-1, row), table_background)
table_actividades.setStyle(tblStyle)
width = 150
height = 150
contents.append(NextPageTemplate('laterpages'))
contents.append(table_actividades)
contents.append(PageBreak())
doc.addPageTemplates([firstpage,laterpages])
doc.build(contents)
结果
有了这个,你可以添加任意数量的记录,我试过 300。table 不是完全可见的,因为为了方便起见,我制作了一个 A4 大小的 pdf。然而,任何尺寸的原理都是一样的,所以你必须玩弄框架的尺寸和pdf页面的尺寸。
EXTRA,每页添加header
由于现在只需要一个模板,因此应删除“first_page”模板,因为它对所有页面都是相同的。按照您一开始提出的相同方式,我每 21 条记录剪切一次 table(以包括 table 的 header),并将其分组到一个列表中,然后迭代添加header 每个循环中都有标志。也包含在逻辑切割语句中,记录数没有达到21条但记录数即将结束的情况。代码如下:
canvas = Canvas(file_name, pagesize=landscape(letter))
doc = BaseDocTemplate(file_name)
contents =[]
width,height = A4
left_header_frame = Frame(
0.2*inch,
height-1.2*inch,
2*inch,
1*inch
)
right_header_frame = Frame(
2.2*inch,
height-1.2*inch,
width-2.5*inch,
1*inch,id='normal'
)
frame_table= Frame(
0.2*inch,
0.7*inch,
(width-0.6*inch)+0.17*inch,
height-2*inch,
leftPadding = 0,
topPadding=0,
showBoundary = 1,
id='col'
)
laterpages = PageTemplate(id='laterpages',frames=[left_header_frame, right_header_frame,frame_table],)
logoleft = Image('logo_power.png')
logoleft._restrictSize(1.5*inch, 1.5*inch)
logoleft.hAlign = 'CENTER'
logoleft.vAlign = 'CENTER'
styleSheet = getSampleStyleSheet()
style_title = styleSheet['Heading1']
style_title.fontSize = 20
style_title.fontName = 'Helvetica-Bold'
style_title.alignment=TA_CENTER
style_data = styleSheet['Normal']
style_data.fontSize = 16
style_data.fontName = 'Helvetica'
style_data.alignment=TA_CENTER
style_date = styleSheet['Normal']
style_date.fontSize = 14
style_date.fontName = 'Helvetica'
style_date.alignment=TA_CENTER
canvas.setTitle(document_title)
title_background = colors.fidblue
hour = 8
minute = 0
hour_list = []
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
i = 0
table_group= []
size = 304
count = 0
for i in range(size):
if minute == 0:
if hour <= 12:
time = str(hour) + ':' + str(minute) + '0 a.m.'
else:
time = str(hour-12) + ':' + str(minute) + '0 p.m.'
else:
if hour <= 12:
time = str(hour) + ':' + str(minute) + ' a.m.'
else:
time = str(hour-12) + ':' + str(minute) + ' p.m.'
if minute != 45:
minute += 15
else:
hour += 1
minute = 0
hour_list.append(time)
data_actividades.append([hour_list[i], i, i, i, i, i, i, i])
i += 1
table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)
tblStyle = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), title_background),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (1, 0), (1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
rowNumb = len(data_actividades)
for row in range(1, rowNumb):
if row % 2 == 0:
table_background = colors.lightblue
else:
table_background = colors.aliceblue
tblStyle.add('BACKGROUND', (0, row), (-1, row), table_background)
table_actividades.setStyle(tblStyle)
if ((count >= 20) or (i== size) ):
count = 0
table_group.append(table_actividades)
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},]
width = 150
height = 150
count += 1
if i > size:
break
contents.append(NextPageTemplate('laterpages'))
for table in table_group:
contents.append(logoleft)
contents.append(FrameBreak())
contents.append(Paragraph(title, style_title))
contents.append(Paragraph(nombre_colaborador + ' - ' + sucursal_colaborador, style_data))
contents.append(Paragraph(fecha_actual, style_date))
contents.append(FrameBreak())
contents.append(table)
contents.append(FrameBreak())
doc.addPageTemplates([laterpages,])
doc.build(contents)
额外-结果:
我正在尝试在使用 ReportLab 生成的 PDF 文件中构建进度计划器。根据一天中的不同时间,时间表将有不同的行:从 8:00 a.m., 8:15 a.m., 8:30 a.m 开始].,等等.
我做了一个循环,在这个循环中会自动计算小时数并填写时间表。但是,由于我的 table 太长,无法完全放入页面中。 (虽然时间表应该在 7:30 p.m. 结束,但它在 2:00 p.m. 被剪掉了。)
期望的结果是在 table 大约有 20 个活动时有一个 PageBreak。在下一页中,header 应该与第一页及下面完全相同,是 table 的延续。每次有必要时都应重复该过程,直到 table.
结束Python代码如下:
from reportlab.pdfgen.canvas import Canvas
from datetime import datetime, timedelta
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, landscape
class Vendedor:
"""
Información del Vendedor: Nombre, sucursal, meta de venta
"""
def __init__(self, nombre_vendedor, sucursal, dia_reporte):
self.nombre_vendedor = nombre_vendedor
self.sucursal = sucursal
self.dia_reporte = dia_reporte
class Actividades:
"""
Información de las Actividades realizadas: Hora de actividad y duración, cliente atendido,
tipo de actividad, resultado, monto venta (mxn) + (usd), monto cotización (mxn) + (usd),
solicitud de apoyo y comentarios adicionales
"""
def __init__(self, hora_actividad, duracion_actividad, cliente, tipo_actividad, resultado,
monto_venta_mxn, monto_venta_usd, monto_cot_mxn, monto_cot_usd, requiero_apoyo, comentarios_extra):
self.hora_actividad = hora_actividad
self.duracion_actividad = duracion_actividad
self.cliente = cliente
self.tipo_actividad = tipo_actividad
self.resultado = resultado
self.monto_venta_mxn = monto_venta_mxn
self.monto_venta_usd = monto_venta_usd
self.monto_cot_mxn = monto_cot_mxn
self.monto_cot_usd = monto_cot_usd
self.requiero_apoyo = requiero_apoyo
self.comentarios_extra = comentarios_extra
class PDFReport:
"""
Crea el Reporte de Actividades diarias en archivo de formato PDF
"""
def __init__(self, filename):
self.filename = filename
vendedor = Vendedor('John Doe', 'Stack Overflow', datetime.now().strftime('%d/%m/%Y'))
file_name = 'cronograma_actividades.pdf'
document_title = 'Cronograma Diario de Actividades'
title = 'Cronograma Diario de Actividades'
nombre_colaborador = vendedor.nombre_vendedor
sucursal_colaborador = vendedor.sucursal
fecha_actual = vendedor.dia_reporte
canvas = Canvas(file_name)
canvas.setPageSize(landscape(letter))
canvas.setTitle(document_title)
canvas.setFont("Helvetica-Bold", 20)
canvas.drawCentredString(385+100, 805-250, title)
canvas.setFont("Helvetica", 16)
canvas.drawCentredString(385+100, 785-250, nombre_colaborador + ' - ' + sucursal_colaborador)
canvas.setFont("Helvetica", 14)
canvas.drawCentredString(385+100, 765-250, fecha_actual)
title_background = colors.fidblue
hour = 8
minute = 0
hour_list = []
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
i = 0
for i in range(47):
if minute == 0:
if hour <= 12:
time = str(hour) + ':' + str(minute) + '0 a.m.'
else:
time = str(hour-12) + ':' + str(minute) + '0 p.m.'
else:
if hour <= 12:
time = str(hour) + ':' + str(minute) + ' a.m.'
else:
time = str(hour-12) + ':' + str(minute) + ' p.m.'
if minute != 45:
minute += 15
else:
hour += 1
minute = 0
hour_list.append(time)
# I TRIED THIS SOLUTION BUT THIS DIDN'T WORK
# if i % 20 == 0:
# canvas.showPage()
data_actividades.append([hour_list[i], i, i, i, i, i, i, i])
i += 1
table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)
tblStyle = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), title_background),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (1, 0), (1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
rowNumb = len(data_actividades)
for row in range(1, rowNumb):
if row % 2 == 0:
table_background = colors.lightblue
else:
table_background = colors.aliceblue
tblStyle.add('BACKGROUND', (0, row), (-1, row), table_background)
table_actividades.setStyle(tblStyle)
width = 150
height = 150
table_actividades.wrapOn(canvas, width, height)
table_actividades.drawOn(canvas, 65, (0 - height) - 240)
canvas.save()
我尝试添加:
if i % 20 == 0:
canvas.showPage()
然而这并没有达到预期的效果。
其他快速说明:尽管我专门对 table 的列标题进行了编码。一旦我 运行 程序,列标题的顺序由于某种原因被修改(参见粘贴的图像)。知道为什么会这样吗?
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
非常感谢您,祝您愉快!
您应该按照官方文档第 5 章“PLATYPUS - 页面布局和排版使用脚本”中的建议使用模板。
基本思想是使用框架,并将要添加的所有信息添加到列表元素中。在我的例子中,我称之为“内容”,使用命令“contents.append(FrameBreak())
”你离开框架并在下一个框架上工作,另一方面,如果你想改变模板的类型,你使用命令“
contents.append(NextPageTemplate('<template_name>'))
"
我的建议:
对于你的情况,我使用了两个模板,第一个是包含带有 sheet 信息的 header 和 table 的第一部分的模板,另一个是模板对应于其余内容。这些模板的名称是firstpage,laterpage.The代码如下:
from reportlab.pdfgen.canvas import Canvas
from datetime import datetime, timedelta
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, landscape
from reportlab.platypus import BaseDocTemplate, Frame, Paragraph, PageBreak, \
PageTemplate, Spacer, FrameBreak, NextPageTemplate, Image
from reportlab.lib.pagesizes import letter,A4
from reportlab.lib.units import inch, cm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER,TA_LEFT,TA_RIGHT
class Vendedor:
"""
Información del Vendedor: Nombre, sucursal, meta de venta
"""
def __init__(self, nombre_vendedor, sucursal, dia_reporte):
self.nombre_vendedor = nombre_vendedor
self.sucursal = sucursal
self.dia_reporte = dia_reporte
class Actividades:
"""
Información de las Actividades realizadas: Hora de actividad y duración, cliente atendido,
tipo de actividad, resultado, monto venta (mxn) + (usd), monto cotización (mxn) + (usd),
solicitud de apoyo y comentarios adicionales
"""
def __init__(self, hora_actividad, duracion_actividad, cliente, tipo_actividad, resultado,
monto_venta_mxn, monto_venta_usd, monto_cot_mxn, monto_cot_usd, requiero_apoyo, comentarios_extra):
self.hora_actividad = hora_actividad
self.duracion_actividad = duracion_actividad
self.cliente = cliente
self.tipo_actividad = tipo_actividad
self.resultado = resultado
self.monto_venta_mxn = monto_venta_mxn
self.monto_venta_usd = monto_venta_usd
self.monto_cot_mxn = monto_cot_mxn
self.monto_cot_usd = monto_cot_usd
self.requiero_apoyo = requiero_apoyo
self.comentarios_extra = comentarios_extra
class PDFReport:
"""
Crea el Reporte de Actividades diarias en archivo de formato PDF
"""
def __init__(self, filename):
self.filename = filename
vendedor = Vendedor('John Doe', 'Stack Overflow', datetime.now().strftime('%d/%m/%Y'))
file_name = 'cronograma_actividades.pdf'
document_title = 'Cronograma Diario de Actividades'
title = 'Cronograma Diario de Actividades'
nombre_colaborador = vendedor.nombre_vendedor
sucursal_colaborador = vendedor.sucursal
fecha_actual = vendedor.dia_reporte
canvas = Canvas(file_name, pagesize=landscape(letter))
doc = BaseDocTemplate(file_name)
contents =[]
width,height = A4
left_header_frame = Frame(
0.2*inch,
height-1.2*inch,
2*inch,
1*inch
)
right_header_frame = Frame(
2.2*inch,
height-1.2*inch,
width-2.5*inch,
1*inch,id='normal'
)
frame_later = Frame(
0.2*inch,
0.6*inch,
(width-0.6*inch)+0.17*inch,
height-1*inch,
leftPadding = 0,
topPadding=0,
showBoundary = 1,
id='col'
)
frame_table= Frame(
0.2*inch,
0.7*inch,
(width-0.6*inch)+0.17*inch,
height-2*inch,
leftPadding = 0,
topPadding=0,
showBoundary = 1,
id='col'
)
laterpages = PageTemplate(id='laterpages',frames=[frame_later])
firstpage = PageTemplate(id='firstpage',frames=[left_header_frame, right_header_frame,frame_table],)
contents.append(NextPageTemplate('firstpage'))
logoleft = Image('logo_power.png')
logoleft._restrictSize(1.5*inch, 1.5*inch)
logoleft.hAlign = 'CENTER'
logoleft.vAlign = 'CENTER'
contents.append(logoleft)
contents.append(FrameBreak())
styleSheet = getSampleStyleSheet()
style_title = styleSheet['Heading1']
style_title.fontSize = 20
style_title.fontName = 'Helvetica-Bold'
style_title.alignment=TA_CENTER
style_data = styleSheet['Normal']
style_data.fontSize = 16
style_data.fontName = 'Helvetica'
style_data.alignment=TA_CENTER
style_date = styleSheet['Normal']
style_date.fontSize = 14
style_date.fontName = 'Helvetica'
style_date.alignment=TA_CENTER
canvas.setTitle(document_title)
contents.append(Paragraph(title, style_title))
contents.append(Paragraph(nombre_colaborador + ' - ' + sucursal_colaborador, style_data))
contents.append(Paragraph(fecha_actual, style_date))
contents.append(FrameBreak())
title_background = colors.fidblue
hour = 8
minute = 0
hour_list = []
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
i = 0
for i in range(300):
if minute == 0:
if hour <= 12:
time = str(hour) + ':' + str(minute) + '0 a.m.'
else:
time = str(hour-12) + ':' + str(minute) + '0 p.m.'
else:
if hour <= 12:
time = str(hour) + ':' + str(minute) + ' a.m.'
else:
time = str(hour-12) + ':' + str(minute) + ' p.m.'
if minute != 45:
minute += 15
else:
hour += 1
minute = 0
hour_list.append(time)
# I TRIED THIS SOLUTION BUT THIS DIDN'T WORK
# if i % 20 == 0:
data_actividades.append([hour_list[i], i, i, i, i, i, i, i])
i += 1
table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)
tblStyle = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), title_background),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (1, 0), (1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
rowNumb = len(data_actividades)
for row in range(1, rowNumb):
if row % 2 == 0:
table_background = colors.lightblue
else:
table_background = colors.aliceblue
tblStyle.add('BACKGROUND', (0, row), (-1, row), table_background)
table_actividades.setStyle(tblStyle)
width = 150
height = 150
contents.append(NextPageTemplate('laterpages'))
contents.append(table_actividades)
contents.append(PageBreak())
doc.addPageTemplates([firstpage,laterpages])
doc.build(contents)
结果
有了这个,你可以添加任意数量的记录,我试过 300。table 不是完全可见的,因为为了方便起见,我制作了一个 A4 大小的 pdf。然而,任何尺寸的原理都是一样的,所以你必须玩弄框架的尺寸和pdf页面的尺寸。
EXTRA,每页添加header
由于现在只需要一个模板,因此应删除“first_page”模板,因为它对所有页面都是相同的。按照您一开始提出的相同方式,我每 21 条记录剪切一次 table(以包括 table 的 header),并将其分组到一个列表中,然后迭代添加header 每个循环中都有标志。也包含在逻辑切割语句中,记录数没有达到21条但记录数即将结束的情况。代码如下:
canvas = Canvas(file_name, pagesize=landscape(letter))
doc = BaseDocTemplate(file_name)
contents =[]
width,height = A4
left_header_frame = Frame(
0.2*inch,
height-1.2*inch,
2*inch,
1*inch
)
right_header_frame = Frame(
2.2*inch,
height-1.2*inch,
width-2.5*inch,
1*inch,id='normal'
)
frame_table= Frame(
0.2*inch,
0.7*inch,
(width-0.6*inch)+0.17*inch,
height-2*inch,
leftPadding = 0,
topPadding=0,
showBoundary = 1,
id='col'
)
laterpages = PageTemplate(id='laterpages',frames=[left_header_frame, right_header_frame,frame_table],)
logoleft = Image('logo_power.png')
logoleft._restrictSize(1.5*inch, 1.5*inch)
logoleft.hAlign = 'CENTER'
logoleft.vAlign = 'CENTER'
styleSheet = getSampleStyleSheet()
style_title = styleSheet['Heading1']
style_title.fontSize = 20
style_title.fontName = 'Helvetica-Bold'
style_title.alignment=TA_CENTER
style_data = styleSheet['Normal']
style_data.fontSize = 16
style_data.fontName = 'Helvetica'
style_data.alignment=TA_CENTER
style_date = styleSheet['Normal']
style_date.fontSize = 14
style_date.fontName = 'Helvetica'
style_date.alignment=TA_CENTER
canvas.setTitle(document_title)
title_background = colors.fidblue
hour = 8
minute = 0
hour_list = []
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},
]
i = 0
table_group= []
size = 304
count = 0
for i in range(size):
if minute == 0:
if hour <= 12:
time = str(hour) + ':' + str(minute) + '0 a.m.'
else:
time = str(hour-12) + ':' + str(minute) + '0 p.m.'
else:
if hour <= 12:
time = str(hour) + ':' + str(minute) + ' a.m.'
else:
time = str(hour-12) + ':' + str(minute) + ' p.m.'
if minute != 45:
minute += 15
else:
hour += 1
minute = 0
hour_list.append(time)
data_actividades.append([hour_list[i], i, i, i, i, i, i, i])
i += 1
table_actividades = Table(data_actividades, colWidths=85, rowHeights=30, repeatRows=1)
tblStyle = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), title_background),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (1, 0), (1, -1), 'CENTER'),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
rowNumb = len(data_actividades)
for row in range(1, rowNumb):
if row % 2 == 0:
table_background = colors.lightblue
else:
table_background = colors.aliceblue
tblStyle.add('BACKGROUND', (0, row), (-1, row), table_background)
table_actividades.setStyle(tblStyle)
if ((count >= 20) or (i== size) ):
count = 0
table_group.append(table_actividades)
data_actividades = [
{'Hora', 'Cliente', 'Resultado de \nActividad', 'Monto Venta \n(MXN)', 'Monto Venta \n(USD)',
'Monto Cotización \n(MXN)', 'Monto Cotización \n(USD)', 'Comentarios \nAdicionales'},]
width = 150
height = 150
count += 1
if i > size:
break
contents.append(NextPageTemplate('laterpages'))
for table in table_group:
contents.append(logoleft)
contents.append(FrameBreak())
contents.append(Paragraph(title, style_title))
contents.append(Paragraph(nombre_colaborador + ' - ' + sucursal_colaborador, style_data))
contents.append(Paragraph(fecha_actual, style_date))
contents.append(FrameBreak())
contents.append(table)
contents.append(FrameBreak())
doc.addPageTemplates([laterpages,])
doc.build(contents)
额外-结果: