How can I print out data table or data grid with virtual printer?like picture shown, I wish that as long as I click ‘print’, I could print out or download data in grid as .pdf or other format file.
This is something you might build into your App, as your very own Server Module function.
When you write code into a Server Module, that code can call upon a wide variety of libraries. A few of them are intended for creating Excel, PDF, etc. files.
Here’s a list of libraries available to your Server Modules:
https://anvil.works/doc/#python_packages
As an example, here’s some code I have in a server function to generate an order invoice. Obviously it won’t work as is in your code, but should give you a starting point.
@anvil.server.callable
def get_order_pdf(order_id):
user = anvil.users.get_user()
if not user:
return None
order = app_tables.orders.get(order_id=order_id)
if not order or (user != order['user'] and not user['admin']):
return None
if order['user']['title']:
full_name = order['user']['title'] + ' ' + order['user']['first_name'] + ' ' + order['user']['last_name']
else:
full_name = order['user']['first_name'] + ' ' + order['user']['last_name']
pdf = FPDF()
pdf.add_page()
# Change this to load the logo image from the database once we have a logo image
logo_image = None
if logo_image:
pdf.image(logo_image, 20, 16, 40)
pdf.ln()
pdf.set_font('Helvetica', 'I', 10)
pdf.cell(190, 7, 'Order Details', 1, 2)
pdf.set_font('Helvetica', '', 10)
y = pdf.get_y()
pdf.cell(95, 8, 'Order Id: ' + order['order_id'], 1)
x = pdf.get_x()
pdf.set_xy(x, y)
pdf.cell(95, 8, 'Date Processed: ' + order['date'].strftime('%b %d, %Y'), 1)
pdf.ln()
pdf.ln()
pdf.set_font('Helvetica', 'I', 10)
pdf.cell(190, 7, 'Account Information', 1, 2)
pdf.set_font('Helvetica', '', 10)
pdf.multi_cell(190, 8, 'Name: ' + full_name + '\nEmail: ' + order['user']['email'], 1)
pdf.ln()
pdf.set_font('Helvetica', 'I', 10)
pdf.cell(190, 7, 'Mysteries', 1, 2)
pdf.set_font('Helvetica', '', 10)
pdf.set_fill_color(200, 200, 200)
pdf.cell(53, 10, 'Mystery Name', 1, 0, '', True)
pdf.cell(53, 10, 'Detective', 1, 0, '', True)
pdf.cell(52, 10, 'Current Stage', 1, 0, '', True)
pdf.cell(32, 10, 'Cost', 1, 0, '', True)
pdf.set_fill_color(255, 255, 255)
order_items = app_tables.orderitems.search(order=order)
for item in order_items:
if item['detective']['title']:
detective_name = item['detective']['title'] + ' ' + item['detective']['first_name'] + ' ' + item['detective']['last_name']
else:
detective_name = item['detective']['first_name'] + ' ' + item['detective']['last_name']
pdf.ln()
pdf.cell(53, 10, item['mystery']['title'], 1)
pdf.cell(53, 10, detective_name, 1)
pdf.cell(52, 10, item['stage']['title'], 1)
pdf.cell(32, 10, '${:,.2f}'.format(item['cost']/100), 1)
pdf.ln()
pdf.set_fill_color(200, 200, 200)
pdf.cell(106, 10, '')
pdf.cell(52, 10, 'Total', 1, 0, 'R', True)
pdf.cell(32, 10, '${:,.2f}'.format(order['total']/100), 1, 0, '', True)
byte_string = pdf.output(dest='S').encode('latin-1')
# Create an Anvil Media object from the encoded bytes.
pdf_media = anvil.BlobMedia("application/pdf", byte_string, name="Invoice.pdf")
return pdf_media
And then in my form, I have a button for downloading the invoice:
def download_button_click(self, **event_args):
invoice = anvil.server.call('get_order_pdf', self.item['order_id'])
if invoice:
download(invoice)
Thank you for sharing solutions! Can I have your copy link again? It is not valid any more. Thanks! @ campopianoa
Oh yes! Sorry about that. I apparently deleted it.
Here’s another one!
Note that it uses Pandas to convert the table to HTML, and Anvil’s download function to download the file.
clone:
https://anvil.works/build#clone:6E2ZGONOPNIANKH7=B75KBBEGROHHTEDRRGNEDJUN
I’m away from the office so I can’t really dig into this deeply at the moment.
Can you print the HTML that was generated with Pandas in the sever function?
That would at least make sure that there is HTML.
I finally found the problem and fixed it. Because I cloned you link and even didn’t modify your function name, it possibly call from your function ‘get_data’ , so I modify the function name and solved it. Thanks for sharing!
My pleasure. Glad you got it working.
Here’s an example of producing a PDF table from a Data Grid. It uses FPDF in a Server Module.
https://anvil.works/build#clone:PJ2CHRCTHTZIJPZF=CK6NFPDAQTTBUCMULLAU6DT5
It creates a PDF table using pyFPDF like so:
@anvil.server.callable
def make_pdf_table(headings, items):
# Set up FPDF
pdf = FPDF()
pdf.add_page()
pdf.set_font('Arial', 'B', 16)
# Set up table spacing
epw = pdf.w - 2*pdf.l_margin
col_width = epw/max(len(items), 1)
th = 1.5*pdf.font_size
# Write the headings
for contents in headings:
pdf.cell(col_width, th, str(contents))
pdf.ln(th)
# Write the table data
pdf.set_font('Arial', '', 16)
for item in items:
for contents in item.values():
pdf.cell(col_width, 1.5*th, str(contents))
pdf.ln(1.5*th)
# Create a Media Object
file_name = '/tmp/table.pdf'
pdf.output(file_name, 'F')
return anvil.media.from_file(file_name, 'application/pdf')
The PDF file gets returned as a Media Object. Downloading that is simple, just use download(media_obj)
. So the download button does this:
def button_download_click(self, **event_args):
"""This method is called when the button is clicked"""
headings = [c['title'] for c in self.data_grid_1.columns]
media_obj = anvil.server.call(
'make_pdf_table', headings, self.repeating_panel_1.items)
)
download(media_obj)
Thank you, very detailed. I would try it later.
Thank you @jshaffstall, it may have been a long time since you posted this response approximately over 2 years now. My question to you Jay or requested to you is by any chance if you still have this invoice application in Anvil do you mind sharing a screenshot to see how it looks as I am trying to create a PDF and in essence an application form and my fields are just dangling in the air. I noticed you use fpdf and that may be something that I need to look into. Thank you again
Sorry, that code doesn’t exist in my app any more, what’s posted above is all that remains.