Chapter 6:
Update existing articles
We can add and read articles in our app. Let’s now build the Update process, which will look like this:
- A popup appears when the user clicks the ’edit’ button
- The popup displays the content of the ‘ArticleEdit’ Form
- The user makes changes
- If the user clicks save, we update the article. Otherwise, we discard the article.
- We refresh the Homepage to reflect any updates
We’ll walk through these steps below.
Step 1: Display a popup when the user clicks the edit button
Go to Design View of your ‘ArticleView’ Form, and drop a Button into the page next to the category_label
. Change its name to edit_article_button
, and its role
to ‘filled-button’. Add the pencil-square
icon instead of text:
We might want to resize the edit_article_button
since its now pushing the category_label
over. Select the ColumnPanel to display blue lines in between its components. You can drag these blue lines to resize the column widths.
We want to display a popup when the user clicks the edit_article_button
. Create an event handler for the edit button by scrolling to the bottom of the Properties Panel and clicking the blue arrows next to ‘click’. The following function will be added to the Form’s code:
def edit_article_button_click(self, **event_args):
"""This method is called when the button is clicked"""
pass
Step 2: Set the content of the popup to the ‘ArticleEdit’ Form
We want to open a popup that allows the user to update an article. We already have the ‘ArticleEdit’ Form which has all the inputs we’ll need, so we’ll also use this Form for updating articles. (Re-using our hard work is great!)
To do this, we first need to import the ‘ArticleEdit’ inside our ‘ArticleView’ Form:
from ..ArticleEdit import ArticleEdit
Next, customise the alert to display the ‘ArticleEdit’ Form:
def edit_article_button_click(self, **event_args):
# Open an alert displaying the 'ArticleEdit' Form
alert(
content=ArticleEdit(),
title="Update Article",
large=True
)
Step 3: The user makes their updates
This time, we’re updating an existing article, so instead of passing an empty dictionary to the ‘ArticleEdit’ form, we pass a copy of the article row from the Data Table that we want to edit.
We copy this row because we want to be able to discard the user’s changes if they click Cancel. If we were to use the original article from the Data Table, we would be editing this row directly, and we wouldn’t be able to discard any changes the user made in error.
You can read more about making it easy to cancel operations in database-backed apps.
Modify the edit_article_button_click
function to pass in a copy of the article to be updated. Let’s also add ‘Save’ and ‘Cancel’ buttons:
def edit_article_button_click(self, **event_args):
# Create a copy of the existing article from the Data Table
article_copy = dict(self.item)
# Open an alert displaying the 'ArticleEdit' Form
# set the `self.item` property of the ArticleEdit Form to a copy of the article to be updated
alert(
content=ArticleEdit(item=article_copy),
title="Update Article",
large=True,
buttons=[("Save", True), ("Cancel", False)]
)
By passing in a copy of the existing article, the ArticleEdit’s self.item
property becomes that copy of the article.
Our ‘ArticleEdit’ form already contains data bindings to self.item
, so any updates the user makes will automatically write back to self.item
, which is the copy of the article that we passed into alert(content=ArticleEdit(item=article_copy))
Step 4: Update the article in your Data Table, or discard it
We’ll use a Server Module to update an existing article in the Data Table.
Add this function to your Server Module:
@anvil.server.callable
def update_article(article, article_dict):
# check that the article given is really a row in the ‘articles’ table
if app_tables.articles.has_row(article):
article_dict['updated'] = datetime.now()
article.update(**article_dict)
else:
raise Exception("Article does not exist")
This function takes two arguments: the existing article, and the updated article.
We’ve added a security check, to first check that the article
we were given is really a row in the ‘articles’ table. If we didn’t make this check, a malicious user could edit any row in any data table by passing it to this function!
This check must occur in a Server Module because server code can be trusted.
Finally, we’ll call update_article
from the client when we want to update a news article. Our ‘Save’ and ‘Cancel’ buttons return the values ‘True’ and ‘False’, respectively, when clicked. If we wrap our alert in an if statement, the code block will be executed if the user clicks ‘Save’.
Change your edit_article_button_click
function to the following:
def edit_article_button_click(self, **event_args):
# Create a copy of the existing article from the Data Table
article_copy = dict(self.item)
# Open an alert displaying the 'ArticleEdit' Form
# set the `self.item` property of the ArticleEdit Form to a copy of the article to be updated
save_clicked = alert(
content=ArticleEdit(item=article_copy),
title="Update Article",
large=True,
buttons=[("Save", True), ("Cancel", False)]
)
# Update the article if the user clicks save
if save_clicked:
anvil.server.call('update_article', self.item, article_copy)
Step 5: Refresh the page to reflect any updates
After updating the article, we call self.refresh_data_bindings
to reflect any changes in the articles as displayed on the Homepage.
Your edit_article_button_click
should look like this:
def edit_article_button_click(self, **event_args):
# Create a copy of the existing article from the Data Table
article_copy = dict(self.item)
# Open an alert displaying the 'ArticleEdit' Form
# set the `self.item` property of the ArticleEdit Form to a copy of the article to be updated
save_clicked = alert(
content=ArticleEdit(item=article_copy),
title="Update Article",
large=True,
buttons=[("Save", True), ("Cancel", False)]
)
# Update the article if the user clicks save
if save_clicked:
anvil.server.call('update_article', self.item, article_copy)
# Now refresh the page
self.refresh_data_bindings()
Run your app and you’ll see that you can now update your articles!
We’ve finished the U in our CRUD app - we can now update articles that already exist!
Only one more letter to go: we’ll make it possible to delete articles. That’s the D in CRUD app.