Web2py – Components ”; Previous Next A component is defined as the functional part of a web page, which works autonomously. It can be composed of modules, controllers and views, which are embedded in a web page. The component in an application, must be localized tag and the performance is considered to be independent of module. In web2py, the main focus is on using components that are loaded in page and which communicate with the component controller via AJAX. web2py includes a function, which is called the LOAD function, which makes implementation of components easy without explicit JavaScript or AJAX programming. Consider a simple web application namely “test” that extends the web2py application with custom model in file “models/db_comments.py”. db.define_table( ”comment_post”, Field(”body”,”text”, label = ”Your comment”),auth.signature ) The above code will create a table “comment_post” with the proper table definition. The action will be implemented with the help of functions in “controllers/comments.py”. def post(): return dict( form = SQLFORM(db.comment_post).process(), comments = db(db.comment_post).select() ) The corresponding view will be displayed as − {{extend ”layout.html”}} {{for post in comments:}} <div class = “post”> On {{= post.created_on}} {{= post.created_by.first_name}} says <span class = “post_body”>{{= post.body}}</span> </div> {{pass}} {{= form}} The page can be accessed using the given URL − http://127.0.0.1:8000/test/comments/post The method mentioned above is a traditional way of accessing a view, which can be changed with the implementation of the LOAD function. This can be achieved by creating a new view with the extension “.load” that does not extend the layout. The new view created would be “views/comments/post.load” − <div class = “post”> On {{= post.created_on}} {{= post.created_by.first_name}} says <blockquote class = “post_body”>{{= post.body}}</blockquote> </div> {{pass}} {{= form}} The URL to access the page would be − http://127.0.0.1:8000/test/comments/post.load The LOAD component can be embedded into any other page of web2py application. This can be done by using the following statement. {{= LOAD(”comments”,”post.load”,ajax = True)}} For example, the Controllers can be edited as − def index(): return dict() In View, we can add the component − {{extend ”layout.html”}} {{= LOAD(”comments”,”post.load”,ajax = True)}} The page can be accessed with the URL − http://127.0.0.1:8000/test/default/index Component Plugins Component plugins are the plugins, which uniquely define Components. Components access the database directly with their model definition. As mentioned in the previous example, comments component into a comments_plugin can be done in the Models section − “models/plugin_comments.py” − db.define_table( ”plugin_comments_comment”, Field(”body”,”text”, label = ”Your comment”), auth.signature ) The Controller will include the following plugin − def plugin_comments(): return LOAD(”plugin_comments”,”post”,ajax = True) Print Page Previous Next Advertisements ”;
Category: web2py
Web2py – Security
Web2py – Security ”; Previous Next In the previous chapters, there was complete information on the implementation of web2py with various tools. The major concern for developing web2py applications includes security from a user’s perspective. The unique features of web2py are as follows − Users can learn the implementation easily. It requires no installation and dependencies. It has been stable since the day of launch. web2py is lightweight and includes libraries for Data Abstraction Layer and template language. It works with the help of Web Server Gateway Interface, which acts as a communication between web servers and applications. Open web application security project (OWASP) is a community, which lists down the security breaches of web application. Security Breaches With respect to OWASP, issues related to web applications and how web2py overcomes them is discussed below. Cross Side Scripting It is also known as XSS. It occurs whenever an application takes a user supplied data and sends it to the user’s browser without encoding or validating the content. The attackers execute scripts to inject worms and viruses using cross side scripting. web2py helps in preventing XSS by preventing all the rendered variables in the View. Information Leakage Sometimes, applications leak information about internal workings, privacy and configurations. Attackers use this to breach sensitive data, which could lead to serious attacks. web2py prevents this by ticketing system. It logs all the errors and the ticket is issued to the user whose error is being registered. These errors are only accessible to the administrator. Broken Authentication Account credentials are not often protected. Attackers compromise on passwords, authentication tokens to steal the user’s identities. web2py provides a mechanism for administrative interface. It also forces to use secure sessions when the client is not “localhost”. Insecure Communications Sometimes applications fail to encrypt the network traffic. It is necessary to manage traffic to protect sensitive communications. web2py provides SSL enabled certificates to provide encryption of communications. This also helps to maintain sensitive communication. Restriction in URL Access Web applications normally protect the sensitive functionality by preventing display of the links and URLs to some users. Attackers can try to breach some sensitive data by manipulating the URL with some information. In wb2py, a URL maps to the modules and functions rather than the given file. It also includes a mechanism, which specifies which functions are public and which are maintained as private. This helps in resolving the issue. Print Page Previous Next Advertisements ”;
Web2py – Email & SMS
Web2py – Email & SMS ”; Previous Next web2py includes functionalities of sending e-mail and SMS to the user. It uses libraries to send emails and sms. Setting Up Email The in-built class namely gluon.tools.Mail class is used to send email in web2py framework. The mailer can be defined with this class. from gluon.tools import Mail mail = Mail() mail.settings.server = ”smtp.example.com:25” mail.settings.sender = ”[email protected]” mail.settings.login = ”username:password” The sender email as mentioned in the above example along with the password will be authenticated each time when an email is sent. If the user needs to experiment or use for some debugging purpose, this can be achieved using the following code. mail.settings.server = ”logging” Now, all the emails will not be sent but it will be logged in the console. Sending an Email Once we have set the configuration settings for an email using mail object, an email can be sent to many users. The complete syntax of mail.send() is as follows − send( to, subject = ”Abc”, message = ”None”, attachments = [], cc = [], bcc = [], reply_to = [], sender = None, encoding = ”utf-8”, raw = True, headers = {} ) The implementation of mail.send() is given below. mail.send( to = [”[email protected]”], subject = ”hello”, reply_to = ”[email protected]”, message = ”Hello ! How are you?” ) Mail returns a Boolean expression based on the response of the mailing server, that the mail is received by the end user. It returns True if it succeeds in sending an email to the user. The attributes to, cc and bcc includes the list of valid email addresses for which the mail is intended to be sent. Sending SMS The implementation for sending SMS messages differs from sending emails in web2py framework as it will require third party service that can relay the messages to the receiver. The third party service is not a free service and will obviously differ based on geographical region (from country to country). web2py uses a module to help sending SMS with the following process − from gluon.contrib.sms_utils import SMSCODES, sms_email email = sms_email(”1 (111) 111-1111”,”T-Mobile USA (abc)”) mail.send(to = email, subject = ”test”, message = ”test”) In the above example, SMSCODES is the dictionary maintained by web2py that maps the names of the major phone companies to the email address postfix. Telephone companies usually treat emails originating from third party services as spam. A better method is that the phone companies themselves relay the SMS. Every phone company includes a unique email address for every mobile number in its storage and the SMS can be sent directly to the email. In the above example, The sms_email function takes a phone number (as a string), which returns the email address of the phone. The scaffolding app includes several files. One of them is models/db.py, which imports four. Classes from gluon.tools include mail libraries as well and defines the various global objects. The scaffolding application also defines tables required by the auth object, such as db.auth_user. The default scaffolding application is designed to minimize the number of files, not to be modular. In particular, the model file, db.py, contains the configuration, which in a production environment, is best kept in separate files. Here, we suggest creating a configuration file − from gluon.storage import Storage settings = Storage() settings.production = False if settings.production: settings.db_uri = ”sqlite://production.sqlite” settings.migrate = False else: settings.db_uri = ”sqlite://development.sqlite” settings.migrate = True settings.title = request. settings.subtitle = ”write something here” settings.author = ”you” settings.author_email = ”[email protected]” settings.keywords = ”” settings.description = ”” settings.layout_theme = ”Default” settings.security_key = ”a098c897-724b-4e05-b2d8-8ee993385ae6” settings.email_server = ”localhost” settings.email_sender = ”[email protected]” settings.email_login = ”” settings.login_method = ”local” settings.login_config = ”” Print Page Previous Next Advertisements ”;
Web2py – Deployment
Web2py – Deployment ”; Previous Next Installation of web2py in Ubuntu (Linux) The following steps are implemented for installation of web2py in the Ubuntu Desktop. Step 1 − Download web2py cd /home mkdir www-dev cd www-dev wget http://www.web2py.com/examples/static/web2py_src.zip Step 2 − After the download is complete, unzip it. unzip -x web2py_src.zip Step 3 − Optionally install the tk library for Python, if you need to access the GUI. sudo apt-get install python-tk Step 4 − To start web2py, access the web2py directory and run web2py. cd web2py python web2py.py The GUI will appear as follows − After installation, each time you run it, web2py will ask you to choose a password. This password is your administrative password. If the password is left blank, the administrative interface will be disabled. Once the server is started, web2py will redirect to the screen with following mentioned URL − http://127.0.0.1:8000/ This will conclude that web2py is perfectly running in Ubuntu desktop. Production Deployment in Ubuntu Step 1 − Installation of all the modules needed to run web2py. Installation of postgreSQL sudo apt-get install postgresql Unzip and open ssh-server sudo apt-get install unzip sudo apt-get install openssh-server Installation of Apache 2 and mod-wsgi sudo apt-get install apache2 sudo apt-get install libapache2-mod-wsgi Step 2 − Installation of web2py in /home/www-data This helps for proper deployment in production environment. sudo apt-get install unzip sudo apt-get install openssh-server cd /home sudo mkdir www-data cd www-data Get the web2py source from the web2py site − sudo wget http://web2py.com/examples/static/web2py_src.zip sudo unzip web2py_src.zip sudo chown -R www-data:www-data web2py Step 3 − Create a self-signed certificate. SSL certificates should be obtained from a trusted Certificate Authority. Maintain an SSL folder with the certificates in it. Step 4 − Edit the apache configuration as per the requirement of production environment. Step 5 − Restart the Apache server and verify if the production environment works for the given IP address. Installing web2py on Windows Although there is a binary distribution for Windows environments (packaging executables and standard libraries), web2py is open source, and can be used with a normal Python installation. This method allows working with the latest releases of web2py, and customizing the python modules to be used. Step 1 − Download the source package from web2py official website − http://www.web2py.com/examples/static/web2py_src.zip and unzip it. As web2py does not require installation, the user can unzip it in any folder. Step 2 − To start it, double-click web2py.py. From the console − cd c:web2py c:python27python.exe web2py.py Step 3 − Here command line parameters can be added (−a to set an admin password, −p to specify an alternate port). The startup options are visible through − C:web2py>c:python27python.exe web2py.py –help Note web2py is written in Python, a portable, interpreted and dynamic language that does not require compilation or complicated installation to run. It uses a virtual machine (such as Java and .Net), and it can transparently byte-compile your source code on the fly when you run your scripts. Functionalities in web2py for Database and Testing It is a software called SQLDesigner which helps in making web2py models and generates the corresponding code. Given below are some of the screenshots − SQLDesigner helps in maintaining the relations of the tables in simple manner and generates the corresponding code in the models of given application. Functional Testing Functional testing involves testing of the functions of components or overall system. It can be based on requirement and business process. web2py comes with a module gluon.contrib.webclient, which performs functional testing in remote and local web2py applications. It is basically designed to understand web2py session and postbacks. All it requires is to import the package such that the functional testing would be implemented on the given module. The syntax to import the package is as follows − from gluon.contrib.webclient import WebClient Print Page Previous Next Advertisements ”;
Web2py – Access Control
Web2py – Access Control ”; Previous Next Authentication Almost every application needs to be able to authenticate users and set permissions. web2py comes with an extensive and customizable role-based access control mechanism.web2py. It also supports the protocols, such as CAS, OpenID, OAuth 1.0, LDAP, PAM, X509, and many more. web2py includes a mechanism known as Role Based Access Control mechanism (RBAC) which is an approach to restricting system access to authorized users. The web2py class that implements RBAC is called Auth. Look at the schema given below. Auth defines the following tables − Sr.No Table Name & Description 1 auth_user stores users” name, email address, password, and status. 2 auth_group stores groups or roles for users in a many-to-many structure 3 auth_membership Stores the information of links users and groups in a many-to-many structure 4 auth_permission The table links groups and permissions. 5 auth_event logs changes in the other tables and successful access 6 auth_cas It is used for Central Authentication Service Customizing Auth There are two ways to customize Auth. To define a custom db.auth_user table from scratch. Let web2py define the auth table. Let us look at the last method of defining the auth table. In the db.py model, replace the following line − auth.define_tables() Replace it with the following code − auth.settings.extra_fields[”auth_user”] = [ Field(”phone_number”,requires = IS_MATCH(”d{3}-d{3}-d{4}”)), Field(”address”,”text”) ] auth.define_tables(username = True) The assumption is that each user consists of phone number, username and address. auth.settings.extra_fields is a dictionary of extra fields. The key is the name of the auth table to which to add the extra fields. The value is a list of extra fields. Here, we have added two extra fields, phone_number and address. username has to be treated in a special way, because it is involved in the authentication process, which is normally based on the email field. By passing the username argument to the following line, it is informed to web2py that we want the username field, and we want to use it for login instead of the email field. It acts like a primary key. auth.define_tables(username = True) The username is treated as a unique value. There may be cases when registration happens outside the normal registration form. It also happens so, that the new user is forced to login, to complete their registration. This can be done using a dummy field, complete_registration that is set to False by default, and is set to True when they update their profile. auth.settings.extra_fields[”auth_user”] = [ Field(”phone_number”,requires = IS_MATCH(”d{3}-d{3}-d{4}”), comment = “i.e. 123-123-1234″), Field(”address”,”text”), Field(”complete_registration”,default = False,update = True, writable = False, readable = False) ] auth.define_tables(username = True) This scenario may intend the new users, upon login, to complete their registration. In db.py, in the models folder, we can append the following code − if auth.user and not auth.user.complete_registration: if not (request.controller,request.function) == (”default”,”user”): redirect(URL(”default”,”user/profile”)) This will force the new users to edit their profile as per the requirements. Authorization It is the process of granting some access or giving permission of something to the users. In web2py once the new user is created or registered, a new group is created to contain the user. The role of the new user is conventionally termed as “user_[id]” where id is the unique identification of the user. The default value for the creation of the new group is − auth.settings.create_user_groups = “user_%(id)s” The creation of the groups among the users can be disabled by − auth.settings.create_user_groups = None Creation, granting access to particular members and permissions can be achieved programmatically with the help of appadmin also. Some of the implementations are listed as follows − Sr.No Command & Usage 1 auth.add_group(”role”, ”description”) returns the id of the newly created group. 2 auth.del_group(group_id) Deletes the group with the specified id 3 auth.del_group(auth.id_group(”user_7”)) Deletes the user group with the given identification. 4 auth.user_group(user_id) Returns the value of id of group uniquely associated for the given user. 5 auth.add_membership(group_id, user_id) Returns the value of user_id for the given group_id 6 auth.del_membership(group_id, user_id) Revokes access of the given member_id i.e. user_id from the given group. 7 auth.has_membership(group_id, user_id, role) Checks whether user_id belongs to the given group. Central Authentication Service (CAS) web2py provides an industry standard namely, Client Authentication Service – CAS for both client and server built-in web2py. It is a third party authentication tool. It is an open protocol for distributed authentication. The working of CAS is as follows − If the user visits the website, the protocol checks whether the user is authenticated. If the user is not authenticated to the application, the protocol redirects to the page where the user can register or log in to the application. If the registration is completed, user receives an email. The registration is not complete until and unless user verifies the email. After successful registration, the user is authenticated with the key, which is used by CAS appliance. The key is used to get the credentials of user via HTTP request, which is set in the background. Print Page Previous Next Advertisements ”;
Web2py – Database Abstraction Layer ”; Previous Next The Database Abstraction Layer (DAL) is considered as the major strength of web2py. The DAL exposes a simple Applications Programming Interface (API) to the underlying SQL syntax. In this chapter, we will get to know the non-trivial applications of DAL, such as building queries to search by tags efficiently and building a hierarchical category tree. Some important features of DAL are − web2py includes a Database Abstraction Layer (DAL), an API which maps Python objects into database objects. The database objects can be queries, tables and records. The DAL dynamically generates the SQL in real time using the specified dialect for the database back end, so that it is not mandatory for a developer to write complete SQL query. The major advantage of using DAL is that the applications will be portable with different kinds of databases. Getting Started with DAL Most applications in web2py require a database connection. Therefore, building the database model is the first step in the design of an application. Consider the newly created application named “helloWorld”. The database is implemented under the Models of the application. All the models for the respective application are comprised under file named − models/db_custom.py. The following steps are used for implementing DAL − Step 1 – DAL Constructor Establish a database connection. This is created using DAL object which is also called the DAL constructor. db = DAL (”sqlite://storage.sqlite”) The notable feature of DAL is that it allows multiple connections with the same database or with different databases, even with different types of database. It is observed that this line is already in the file models/db.py. Therefore, you may not need it, unless you deleted it or need to connect to a different database. By default, web2py connects to a SQLite database stored in file storage.sqlite. This file is located in the application”s databases folder. If the file is absent, it is created by web2py when the application is first executed. SQLite is fast, and stores all the data in one single file. This means that your data can be easily transferred from one application to another. In fact, the SQLite database(s) are packaged by web2py together with the applications. It provides full SQL support, including translations, joins, and aggregates. There are two disadvantages of SQLite. One is that it does not enforce column types, and there is no ALTER TABLE except for adding and dropping columns. The other disadvantage is that the entire database is locked by any transaction that requires write access. Step 2 – Table Constructor Once the connection with database is established, we can use the define_table method to define new tables. For example − db.define_table(”invoice”,Field(”name”)) The above method is also used among Table constructor. The syntax for the table constructor is the same. The first argument is the table name, and it is followed by a list of Field(s). The field constructor takes the following arguments − Sr.No Arguments & Usage 1 The field name Name of the field in table. 2 The field type takes values having any of the datatypes such as string (default), text, boolean, integer and so on. 3 Length Defines the maximum length. 4 default = None This is the default value when a new record is inserted. 5 update = None This works the same as default, but the value is used only on update, not on insert. 6 Notnull This specifies whether the field value can be NULL or not. 7 readable = True This specifies whether the field is readable in forms or not. 8 writable = True This specifies whether the field is writable in forms or not. 9 label = “Field Name” This is the label to be used for this field in forms. The define_table method also takes three named arguments − Syntax db.define_table(”….”,migrate=True, fake_migrate=False, format = ”%(id)s”) migrate = True − This instructs web2py to create the table if it does not exist, or alter it if it does not match the model definition. fake_migrate = False − If the model matches the database table content, then set fake_migrate = True which helps web2py to rebuild a data. format = ”%(id)s” − This is a format string that determines how records on the given table should be represented. Generating Raw SQL Using DAL, we can establish a connection to database and create new tables and their fields using the table constructor and field constructor. Sometimes, it is necessary to generate SQL statements to conform to the necessary output. web2py includes various functions, which help in generating raw SQL, which are given as follows − _insert It helps in fetching insert statements for the given table. For example, print db.person._insert(name =”ABC”) It will retrieve the insert statement for table named “person”. SQL statement output − INSERT INTO person(name) VALUES (”ABC”); _count It helps in fetching SQL statement, which gives the count of records. For example, consider a table named ‘person’ and we need to find the count of persons with name ‘ABC’. print db(db.person.name ==” ABC ”)._count() SQL statement output − SELECT count(*) FROM person WHERE person.name = ” ABC ”; _select It helps in fetching select SQL statements. For example, consider a table named ‘person’ and we need to find the list of persons with name ‘ABC’. print db(db.person.name == ” ABC ”)._select() SQL statement output − SELECT person.name FROM person WHERE person.name = ” ABC ”; _delete It helps in fetching the delete SQL statements. For example, consider for table named ‘person’ and we need to delete the statements with name ‘ABC’ print db(db.person.name == ” ABC ”)._delete() SQL statement output − DELETE FROM person WHERE person.name = ” ABC ”;4 _update It helps in fetching updated SQL statements. For example, consider for table named ‘person’ and we need to update a column name with some other value. print db(db.person.name == ” ABC ”)._update() SQL statement output − UPDATE person SET WHERE person.name = ’Alex’; Issues with DAL (Gotchas)
Web2py – Forms & Validators
Web2py – Forms & Validators ”; Previous Next web2py comes with powerful functions for form generation. Four distinct ways to build forms in web2py are as follows − FORM − In terms of HTML helpers, it is considered as a low-level implementation. A FORM object is aware of its field contents. SQLFORM − It provides the functionalities of Create, Update and Delete to the existing database. SQLFORM.factory − It is considered as abstraction layer on the top of SQLFORM, which generates a form similar to SQLFORM. Here, there is no need to create a new database. CRUD Methods − As the name suggests, it provides Create, Retrieve, Update and Delete features with the similar functionalities based on SQLFORM. FORM Consider an application, which accepts an input from the user and has a “submit” button to submit the response. Controller “default.py” controller will include the following associated function def display_form(): return dict() View The associated view “default/display_form.html” will render the display of form in HTML as − {{extend ”layout.html”}} <h2>Basic Form</h2> <form enctype = “multipart/form-data” action = “{{= URL()}}” method = “post”> Your name: <input name = “name” /> <input type = “submit” /> </form> <h2>Submitted variables</h2> {{= BEAUTIFY(request.vars)}} The above example is the normal HTML form, which asks for the user input. The same form can be generated with the helpers like FORM object. Controller def display_form(): form = FORM(”Value:”, INPUT(_value = ”name”), INPUT(_type = ”submit”)) return dict(form = form) The above function in “default.py” controller includes FORM object (HTML helper) which helps in creation of form. View {{extend ”layout.html”}} <h2>Basic form</h2> {{= form}} <h2>Submitted variables</h2> {{= BEAUTIFY(request.vars)}} He form which is generated by the statement {{= form}} serializes the FORM object. When a user fills the form and clicks on the submit button, the form self-submits, and the variable request.vars.value along with its input value is displayed at the bottom. SQLFORM It helps in creation of a form to the existing database. The steps for its implementation are discussed below. Establishing connection with database using DAL, this is created using DAL object which is also called DAL constructor. After establishing the connection, user can create the respective table. db = DAL(”sqlite://storage.sqlite”) db.define_table(”employee”, Field(”name”, requires = IS_NOT_EMPTY())) Thus, we have created a table named “employee”. The controller builds the form and button with the following statements − form = SQLFORM( db.mytable, record = mytable_index, deletable = True, submit_button = T(”Update”) ) Therefore, for the employee table created, the modification in the controller would be − def display_form(): form = SQLFORM(db.person) There is no modification in View. In the new controller, it is necessary build a FORM, since the SQLFORM constructor built one from the table db.employee is defined in the model. The new form, when serialized, appears as follows − <form enctype = “multipart/form-data” action = “” method = “post”> <table> <tr id = “employee_name__row”> <td> <label id = “person_name__label” for = “person_name”>Your name: </label> </td> <td> <input type = “text” class = “string” name = “name” value = “” id = “employee_name” /> </td> <td></td> </tr> <tr id = “submit_record__row”> <td></td> <td><input value = “Submit” type = “submit” /></td> <td></td> </tr> </table> <input value = “9038845529” type = “hidden” name = “_formkey” /> <input value = “employee” type = “hidden” name = “_formname” /> </form> All tags in the form have names derived from the table and field name. An SQLFORM object also deals with “upload” fields by saving uploaded files in the “uploads” folder. This is done automatically. SQLFORM displays “Boolean” values in the form of checkboxes and text values with the help of “textareas”. SQLFORM also uses the process method.This is necessary if the user wants to keep values with an associated SQLFORM. If form.process(keepvalues = True) then it is accepted. Example def display_form(): form = SQLFORM(db.employee) if form.process().accepted: response.flash = ”form accepted” elif form.errors: response.flash = ”form has errors” else: response.flash = ”please fill out the form” return dict(form = form) SQLFORM.factory Sometimes, the user needs to generate a form in a way that there is an existing database table without the implementation of the database. The user simply wants to take an advantage of the SQLFORM capability. This is done via form.factory and it is maintained in a session. def form_from_factory(): form = SQLFORM.factory( Field(”your_name”, requires = IS_NOT_EMPTY()), Field(”your_image”, ”upload”)) if form.process().accepted: response.flash = ”form accepted” session.your_name = form.vars.your_name session.your_image = form.vars.your_image elif form.errors: response.flash = ”form has errors” return dict(form = form) The form will appear like SQLFORM with name and image as its fields, but there is no such existing table in database. The “default/form_from_factory.html” view will represent as − {{extend ”layout.html”}} {{= form}} CRUD Methods CRUD is an API used on top of SQLFORM. As the name suggests, it is used for creation, retrieval, updating and deletion of appropriate form. CRUD, in comparison to other APIs in web2py, is not exposed; therefore, it is necessary that it should be imported. from gluon.tools import Crud crud = Crud(db) The CRUD object defined above provides the following API − Sr.No API & Functionality 1 crud.tables() Returns a list of tables defined in the database. 2 crud.create(db.tablename) Returns a create form for the table tablename. 3 crud.read(db.tablename, id) Returns a read-only form for tablename and record id. 4 crud.delete(db.tablename, id) deletes the record 5 crud.select(db.tablename, query) Returns a list of records selected from the table. 6 crud.search(db.tablename) Returns a tuple (form, records) where form is a search form. 7 crud() Returns one of the above based on the request.args(). Creation of Form Let us create a form. Follow the codes given below. Model A new model is created under the models folder of the application. The name of the file would be “dynamic_search.py”. def build_query(field, op, value): if op == ”equals”: return field == value elif op == ”not equal”: return field != value elif op == ”greater than”: return field > value elif op == ”less than”: return field < value elif op == ”starts with”: return field.startswith(value) elif op