User Server Module

Backend databases

The User table that we have been dealing with is actually inside a database. At the moment the database has only one table, but eventually we will add extra tables to it. There are four basic operations that databases need to do - create, read, update and delete, referred to as CRUD. We have already been using a read operation, the built in get_user().

CRUD

CRUD stands for Create, Read, Update, and Delete. These are the four basic operations that are fundamental to database management:

  • Create: These operations add new records to a database.

  • Read: These operations retrieve data from the database.

  • Update: These operations modify existing records in the database.

  • Delete: These operations remove records from the database.

All database operations occur server-side (backend). Server-side code provides methods that can be called by the client-side (frontend). When the client-side calls the methods, the server executes the server-side code and then sends the results back to the client-side.

frontend backend

To provide additional, custom methods we will need to create our first server-side code. We will call this module user-service as it will provide CRUD operations to user data.

Code

To start we will need to create a Server Module.

  1. Go to the file submenu

  2. Click on Add Server Module

  3. Then name the new server module user_service

add server module

Making a callable method

If you look at the comment in the user_service it tells you how to create callable function for your server code. Making a function callable allows it to be used in the client-side code.

To make a function callable, you need to add @anvil.server.callable above it. This is called a decorator. Decorators are a bit beyond the scope of this course, and this is the only place that you will use them, so for our purposes, just use it as is.

Decorators

Python decorators can change how other functions work. When you use a decorator, you attach it to another function to change its behavior. This lets you add extra features to your function without changing its main code.

More information can be found at Free Code Camps - Python Decorators Explained For Beginners

Create the update user function

So to create a function for our website to use we must:

  • create a function that accepts a first name and last name

  • get’s the current user

  • updates the current user’s first name and last name with the values provided

  • then add the @anvil.server.callable decorator above the function

Remove all the comments within user_services, then add the code below:

 7@anvil.server.callable
 8def update_user(first_name, last_name):
 9  user = anvil.users.get_user()
10
11  user["first_name"] = first_name
12  user["last_name"] = last_name

Code explaination

  • line 7:

    • @anvil.server.callable → the decorator that allows the client-side code to call this function

  • line 8:

    • def update_user → names the functionupdate_user

    • (first_name, last_name) → requires the values first_name and last_name to be passed when called

  • line 9:

    • anvil.users.get_user() → get the details of the current user. Note these details are stored in a dictionary

    • user = → stores the dictionary of the current user details in a variable called user

  • line 11:

    • user["first_name"] = first_name → change the first_name value of the user to the first_name passed to the function.

  • line 12:

    • user["last_name"] = last_name → change the last_name value of the user to the last_name passed to the function.

Call the update user function

Now that we have the a server-side function we need to call it, so return to the code of SetDetailsComponent.

Replace line 30 with the highlighted text.

17  def button_save_click(self, **event_args):
18    
19    if self.text_box_first_name.text == "":
20      self.label_error.text = "First name cannot be blank"
21      self.label_error.visible = True
22      return
23
24    if self.text_box_last_name.text == "":
25      self.label_error.text = "Last name cannot be blank"
26      self.label_error.visible = True
27      return
28
29    self.label_error.visible = False
30    anvil.server.call("update_user", 
31                    self.text_box_first_name.text, 
32                    self.text_box_last_name.text)

Code explaination

Note: lines 30 - 32 are one statement, it has just been spread over three lines to make it easier to read (you can split arguements after a ,).

  • line 30:

    • anvil.server.call → this is how you call functions that have the @anvil.server.callable decorator

    • "update_user" → when using anvil.server.call the first argument passed is the name of the function you want to call.

    • self.text_box_first_name.text → the text of the first name text box that will passed as first_name to the update_user function.

    • self.text_box_last_name.text → the text of the last name text box that will passed as last_name to the update_user function.

Testing

Time to test if this all works.

  1. Go to the User table and delete your users

  2. Launch your website

  3. Register a new user

  4. Enter a first name and last name

  5. Click on Save Details

  6. Stop your website

  7. Go to the User table and check that your new user has the correct first_name and last_name.

test

Final code state

By the end of this tutorial your code should be the same as below:

Final SetDetailsForm

 1from ._anvil_designer import SetDetailsComponentTemplate
 2from anvil import *
 3import anvil.server
 4import anvil.tables as tables
 5import anvil.tables.query as q
 6from anvil.tables import app_tables
 7import anvil.users
 8
 9
10class SetDetailsComponent(SetDetailsComponentTemplate):
11  def __init__(self, **properties):
12    # Set Form properties and Data Bindings.
13    self.init_components(**properties)
14
15    # Any code you write here will run before the form opens.
16
17  def button_save_click(self, **event_args):
18    
19    if self.text_box_first_name.text == "":
20      self.label_error.text = "First name cannot be blank"
21      self.label_error.visible = True
22      return
23
24    if self.text_box_last_name.text == "":
25      self.label_error.text = "Last name cannot be blank"
26      self.label_error.visible = True
27      return
28
29    self.label_error.visible = False
30    anvil.server.call("update_user", 
31                      self.text_box_first_name.text, 
32                      self.text_box_last_name.text)

Final user_service

 1import anvil.users
 2import anvil.tables as tables
 3import anvil.tables.query as q
 4from anvil.tables import app_tables
 5import anvil.server
 6
 7@anvil.server.callable
 8def update_user(first_name, last_name):
 9  user = anvil.users.get_user()
10
11  user["first_name"] = first_name
12  user["last_name"] = last_name