Table of contents
1.
Introduction
2.
Computed Fields
3.
Virtual Fields
3.1.
New style virtual fields
3.2.
Old style virtual fields
4.
Frequently Asked Questions
4.1.
What is web2py?
4.2.
Why web2py?
4.3.
What is meant by Web application framework?
4.4.
What is Database Abstraction Layer?
4.5.
What is API?
5.
Conclusion
Last Updated: Mar 27, 2024
Easy

Computed Fields and Virtual Fields in web2py

Author Sanchit Kumar
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Sometimes while using web2py, one might wonder what will happen if we do not provide value for a field, how situations will vary if we do not store the value in the database and what to do to simplify the user's code without requiring additional storage.

web2py

To find answers to these questions, let us learn about computed fields and virtual fields one by one with examples.

Computed Fields

Computed Fields

Database Abstraction Layer fields may have a compute attribute. This has to be a function (or lambda) that accepts a Row object and returns a value for the field. Web2py tries to compute from the values of the other fields using this compute function when a new record is modified, including both updates and insertions, if a value for the field is not provided.

>>> db.define_table('item',
...                 Field('up_unit_price', 'double'),
...                 Field('qty_quantity', 'integer'),
...                 Field('tp_total_price',
...                       compute=lambda r: r['up_unit_price'] * r['qty_quantity']))
<Table item (id, up_unit_price, qty_quantity, tp_total_price)>
>>> rid = db.item.insert(up_unit_price=2.99, qt_quantity=6)
>>> db.item[rid]
<Row {'tp_total_price': '17.94', 'up_unit_price': 2.99, 'id': 1L, 'ty_quantity': 6L}>
You can also try this code with Online Python Compiler
Run Code


Note - 

  • The computed value is stored in the database and is not computed upon retrieval.
  • The computed fields are evaluated in the same order in which they are defined in the table definition.

There are two common applications of computed fields:

  • In wiki applications - to avoid re-processing on every request, storing the processed input wiki text as HTML.
  • For searching - to evaluate normalized values for a field, to be utilized for searching.

Virtual Fields

As in the previous subsection, virtual fields are also computed fields, but they differ as they are virtual in the sense that they are not kept in the database and are instead computed each time records are extracted from DB (database). They cannot be used for searching, but they can be used to simplify the code of the user without requiring additional storage.

Virtual Fields are not stored in the Database.

New style virtual fields

This section is marked experimental

A new and easier method of defining virtual fields and lazy virtual fields is provided by web2py.

Let us consider the following model:

db.define_table('item',
                Field('up_unit_price', 'double'),
                Field('qty_quantity', 'integer'))
You can also try this code with Online Python Compiler
Run Code


total_price virtual field can be defined as:

db.item.tp_total_price = Field.Virtual(lambda row: row.item.up_unit_price * row.item.qty_quantity)
You can also try this code with Online Python Compiler
Run Code


That is by simply defining a new field tp_total_price to be a Field.Virtual. A function which takes a row and returns the computed values is the constructor's only argument.

When the records are selected, a virtual field specified as the one above is automatically computed for all records:

for row in db(db.item).select():
    print row.tp_total_price
You can also try this code with Online Python Compiler
Run Code


Additionally, method fields may be defined, which are calculated on-demand when called.

For example -

db.item.dt_discounted_total = \
    Field.Method(lambda row, discount=0.0:
                 row.item.up_unit_price * row.item.qty_quantity * (100.0 - discount / 100))
You can also try this code with Online Python Compiler
Run Code


In this instance, row.dt discounted total is a function and not a value. The function takes the same arguments like the function passed to the Method constructor except for row that is implicit (think of it as self for objects).

The lazy field in the previous example above allows one to figure out the total price for each item:

for row in db(db.item).select(): print row.dt_discounted_total()
You can also try this code with Online Python Compiler
Run Code


Additionally, it permits an optional discount percentage to be passed (let's say 22%):

for row in db(db.item).select(): print row.dt_discounted_total(22)
You can also try this code with Online Python Compiler
Run Code


When a table is defined, virtual and method fields can also be defined in place:

db.define_table('item',
                Field('up_unit_price', 'double'),
                Field('qty_quantity', 'integer'),
                Field.Virtual('tp_total_price', lambda row: ...),
                Field.Method('dt_discounted_total', lambda row, discount=0.0: ...))
You can also try this code with Online Python Compiler
Run Code
Mind That

Old style virtual fields

A container class can be defined, instantiated, and linked to a table or a select in order to define one or more virtual fields. Take the following table, 

For example -

db.define_table('item',
                Field('up_unit_price', 'double'),
                Field('qty_quantity', 'integer'))
total_price virtual field can be defined as:
class My_Virtual_Fields(object):
    def tp_total_price(self):
        return self.item.up_unit_price * self.item.qty_quantity

db.item.virtualfields.append(My_Virtual_Fields())
You can also try this code with Online Python Compiler
Run Code


Note - Every method of the class that only accepts one argument (self) is a new virtual field, as you can see. self refers to each one row of the select. The full path is used to refer to field values, as in self.item.up_unit_price. By appending an instance of the class to the virtualfields attribute of the table, the virtual fields are linked to the table.

Recursive fields can also be accessed using virtual fields, as in:

db.define_table('item',
                Field('up_unit_price', 'double'))

db.define_table('order_item',
                Field('item', 'reference item'),
                Field('qty_quantity', 'integer'))

class My_Virtual_Fields(object):
    def tp_total_price(self):
        return self.order_item.item.up_unit_price * self.order_item.qty_quantity

db.order_item.virtualfields.append(My_Virtual_Fields())
You can also try this code with Online Python Compiler
Run Code


Note - The recursive field access self.order_item.item.up_unit_price where self is the looping record.

They can also act to a JOIN's result:

rows = db(db.order_item.item == db.item.id).select()

class My_Virtual_Fields(object):
    def tp_total_price(self):
        return self.item.up_unit_price * self.order_item.qty_quantity

rows.setvirtualfields(order_item=My_Virtual_Fields())

for row in rows:
    print row.order_item.tp_total_price
You can also try this code with Online Python Compiler
Run Code


Take note of how the syntax is different in this instance. The virtual field accesses both self.item.up_unit_price and self.order_item.qty_quantity that belong to the join select. Using the setvirtualfields method of the rows object, the virtual field is attached to the table's rows. This method can be used to set numerous virtual fields, defined in multiple classes, and attach them to multiple tables, and it accepts an arbitrary number of named arguments:

class My_Virtual_Fields1(object):
    def discounted_up_unit_price(self):
        return self.item.up_unit_price * 0.90

class My_Virtual_Fields2(object):
    def tp_total_price(self):
        return self.item.up_unit_price * self.order_item.qty_quantity
    def discounted_tp_total_price(self):
        return self.item.discounted_up_unit_price * self.order_item.qty_quantity

rows.setvirtualfields(item=My_Virtual_Fields1(),
                      order_item=My_Virtual_Fields2())

for row in rows:
    print row.order_item.discounted_tp_total_price
You can also try this code with Online Python Compiler
Run Code


Virtual fields can be lazy; all they require to do is return a function and access that by calling the function:

db.define_table('item',
                Field('up_unit_price', 'double'),
                Field('qty_quantity', 'integer'))

class My_Virtual_Fields(object):
    def lazy_tp_total_price(self):
        def lazy(self=self):
            return self.item.up_unit_price * self.item.qty_quantity
        return lazy

db.item.virtualfields.append(My_Virtual_Fields())

for item in db(db.item).select():
    print item.lazy_tp_total_price()
You can also try this code with Online Python Compiler
Run Code


or shorter using a lambda function:

class My_Virtual_Fields(object):
    def lazy_tp_total_price(self):
        return lambda self=self: self.item.up_unit_price * self.item.qty_quantity
You can also try this code with Online Python Compiler
Run Code

Frequently Asked Questions

What is web2py?

Web2py is a web application framework which is free and open-source, written in the Python programming language.

Why web2py?

Users can learn easily server-side web development, and it is lightweight and speedy.

What is meant by Web application framework?

A software framework known as a web application framework (WAF) is made to facilitate the creation of web applications, which include web resources, web services, and web APIs.

What is Database Abstraction Layer?

A database abstraction layer is an API (Application Programming Interface) which unifies the communication between a computer application and databases such as Oracle, SQL Server, MySQL, IBM Db2 and PostgreSQL.

What is API?

API (Application Programming Interface) is a means of communication between two or more computer programs. It is a kind of software interface that provides a service to other software programs.

Conclusion

In this article, we discussed Computed fields and Virtual fields in web2py. We understood the concept of computed fields and virtual fields of the database abstraction layer in web2py with examples in code form.

To learn more about Web2Py, see Web2pyWeb2Py initWeb2py IntroductionWeb2Py InstallationTroubleshooting, and Application creation.

Nevertheless, you may consider our paid courses to give your career an edge over others.

Do upvote our blogs if you find them helpful and engaging!

Happy Learning!

Coding Ninjas
Live masterclass