What I’m trying to do: I’m new to Anvil. I’m trying to use python-docx to edit docx file saved to db. I have individual plan, so python-docx should be available to use. I read through the documentation, but I’m still getting error after error. The python-docx code runs just fine on my IDE.
What I’ve tried and what’s not working: I’ve downloaded a blank docx onto db. I’ve tried to use uplink and server code to write to blank docx using python-docx. The python-docx code works just fine on my IDE. However, I’ve tried many different ways to write to the docx on my db. No luck. I’ve also tried to create a new docx in server code using python-docx and save to db. No luck.
Code Sample:
from docx import Document
@anvil.server.callable
def save_doc(doc):
save_new_doc(doc)
@tables.in_transaction
def save_new_doc(doc):
app_tables.mydocs.add_row(docs=doc)
@anvil.server.callable
def write_media_to_file(media_object):
with anvil.media.TempFile(media_object) as file_name:
return file_name
@anvil.server.callable
def edit_doc_server():
doc = Document()
par = doc.add_paragraph()
par.add_run("Hello, world!")
@anvil.server.callable
def write_to_a_file(temp_file_name):
with open(temp_file_name, 'w+') as f:
f.write(anvil.server.call('edit_doc_server')
Client Code:
def button_edit_click(self, **event_args):
"""This method is called when the button is clicked"""
doc = app_tables.mydocs.search()[0]['docs']
temp_file_name = anvil.server.call('write_media_to_file', doc)
anvil.server.call('write_to_a_file', temp_file_name)
I’m new to this, so I could easily be making a mistake. I primarily want to know how I can use python-docx to edit or create docx on Anvil in order to download to browser. Thanks in advance for any help.
When working with server functions it’s good practice to avoid using anvil.server.call so much. If you rewrite the logic you only need 1 of those functions decorated with anvil.server.call.
When you do anvil.server.call you are creating a new call context. A common question on the forum is why don’t global variables work in server modules? The same problem is being seen here. Data is not persisting between server calls.
You only need to use anvil.server.call if you want to communicate to a server function from the client (or to communicate between uplink and server functions). When you’re already in the server just call the function.
e.g.
@anvil.server.callable
def write_to_a_file(temp_file_name):
with open(temp_file_name, 'w+') as f:
f.write(anvil.server.call('edit_doc_server'))
becomes
def write_to_a_file(temp_file_name):
with open(temp_file_name, 'w+') as f:
f.write(edit_doc_server())
It might also be worth accessing the table from the server rather than the client.
I think you can adjust your client code to
def button_edit_click(self, **event_args):
"""This method is called when the button is clicked"""
anvil.server.call('update_doc')
# update_doc is the only function that should be decorated
Thank you for the response, stucork. Could you please tell me why this very simple python-docx app causes a SerializationError? I can’t get past this point. Thank you in advance.
When saving to datatables, Anvil can only save what it can serialize.
A docx object can’t be serialized so can’t be saved.
We need to convert it to a media object which anvil knows how to handle.
import io
content = io.BytesIO()
doc.save(content)
content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
media_object = anvil.BlobMedia(content_type=content_type, content=content.getvalue(), name="hello.docx")
# now save the media object to the datatable
# you can also return the media object and download it on the client
(I got the content type from searching for mimetypes in google and looking up docx) (It also works with None as the content type and this will be inferred when you download the doc)