Before starting

Get ready for this 8 minutes tutorial that will take you from the download to a running web application. This sample case will be an application of video catalog, with web interface and a simplesqlite database.

Framework installation and GenroHome

When you install GenroPy-framework, a new directory tree is been created at your /usr/local/ path. The path /usr/local/genro is called GenroHome, we suggest to set /usr/local/genro/bin in your profile PATH to use easily the following bin commands.

Here's how GenroHome is structured:

  • bin
  • data: will contain application instances and sites
  • lib: contains jasvascript libraries
  • packages: contains some ready packages. You can put yours here.

External requirements

Now you need something else to make GenroApplication work.

  • Apache2
  • mod_python
  • sqlite
  • pysqlite
  • Dojo

Rename the Dojo directory as dojo and move it at path /usr/local/genro/lib.

Creating a sample package

Since we said that an application is a collection of one or more packages, we have to start from the package itself. As first step let's make a sample package for a video-catalog management, called video. In order to do this, we use the command gnrmkpackage that creates an empty package into the current directory.

With the following instruction we are going to create the video package into the /usr/local/genro/packages directory.

gnrmkpackage video

Describing the database model

The directories lib, model, webpages are empty, and here is the main.py code:

#!/usr/bin/env python
# encoding: utf-8

class Package(object):
    def config_attributes(self):
        return dict(comment='video package',
                    name_short='video', 
                    name_long='video', 
                    name_full='video')
        
    def config_db(self, pkg):
        testtbl = pkg.table('test')
        testtbl.stringColumn('id', len_max='22').isPkey()

Now we have to implement the methods config_attributes and config_db for our purposes.

The first sets metadata on the package:

 def config_attributes(self):
        return dict(comment='A package for video catalog management',
                    name_short='video',
                    name_long='Video Catalog', 
                    name_full='Video Catalog')
    

The method config_db defines the database model source, composed as follows:

  • director
    • id (pkey)
    • name
    • year
    • nationality
  • movie
    • id (pkey)
    • title
    • genre
    • director (related with director.id)
    • year
    • nationality
    • description

  • dvd
    • code (pkey)
    • movieid (related with movie.id)
    • purchasedate
    • available
def config_db(self,pkg):
    director = pkg.table('director', name_short='Dir', name_long='Director', 
                     pcol='name,year:%s (%s)')
    dir_id = director.intColumn('id')
    director.pkey('id')
    director.column('name', name_short='N.', name_long='Name')
    director.intColumn('year', name_short='Yr', name_long='Birth Year')
    director.column('nationality', name_short='Ntl',name_long='Nationality')

    movie = pkg.table('movie', name_short='Mv',name_long='Movie', pcol='title')
    movie_id = movie.intColumn('id')
    movie.pkey('id')
    movie.column('title', name_short='Ttl.',name_long='Title',
                        validate_case='capitalize', validate_len='3,40')
    movie.column('genre', name_short='Gnr',name_long='Genre',
                        validate_case='upper', validate_len='3,10')
    movie.column('director', name_short='Dir',name_long='Director').relate(dir_id)
    movie.intColumn('year', name_short='Yr',name_long='Year')
    movie.column('nationality', name_short='Ntl', name_long='Nationality')
    movie.column('description', name_short='Dsc', name_long='Movie description')

    dvd = pkg.table('dvd', name_short='Dvd', name_long='Dvd')
    dvd_id = dvd.intColumn('code')
    dvd.pkey('code')
    dvd.column('movieid', name_short='Mid', name_long='Movie id').relate(movie_id)
    dvd.dateColumn('purchasedate', name_short='Pdt', name_long='Purchase date')
    dvd.column('available', name_short='Avl', name_long='Available')

Creating the page

Now the database model is ready, let's prepare the first package's webpage. movieinfo.py The page structure is very simple and composed by:

  • Page layout container
    • Title header
    • Left column
      • Select widget
    • Client pane
      • Box with movie informations

We use just one complex widget called dbSelect. It is a field that makes realt-time queries on a database table and displays in a popup menu all results that starts with the typed substring. When the user choose one result rom the menu it auto-fills the field and load from server the selected record in the page's data bag. This widget must be configured passing the db table (dbtable), the column to show (dbfield) and the path of page's data bag where the record must be saved into (recordpath).

Here's the GnrWebPage implementation.

class GnrCustomWebPage(GnrWebPage): 
	
# ----- Page description -----
	          
    def main(self, root, **kwargs):
		
	# ----- page layout -----
	layout = root.layoutContainer(height='100%',background_color='silver')
		
	# ----- title header ------
	header = layout.contentPane(layoutAlign='top', 
		                            background_color='maroon')
	title = header.div('Movies', color='white', text_align='center', font_size='18pt')
	
        #------dbSelect --------------
	left = layout.contentPane(layoutAlign='left', width='30em', padding='1em')
	left.span('Select a movie', margin_right='10px')
	movie_selector = left.dbSelect(gnrId='film_selector',
		                        dbtable='video.movie', 
		                        dbfield="title",
                                        recordpath='film.record', 
		                        _class='linkerselect')
		
	# ----- client pane with information box ----- 
	client= layout.contentPane(layoutAlign='client')		
	movie_info=client.div(datasource='film.record',
                                         border='inset 1px', height='5em', width='20em',
                                         padding='1em', margin='1em',
                                         background_color='#CCCCFF')

	movie_info.span(datasource=':title', font_weight='bold', font_size='12pt')
	movie_info.br()
	movie_info.span(datasource=':genre', mask='%s ')
	movie_info.span(datasource=':nationality', mask='(%s ')
	movie_info.span(datasource=':year', mask='-%s)')
	movie_info.br()
	movie_info.span(datasource=':@director.name', mask=' directed by %s ')

   
# ------------ Standard Rpc Call ------------
def rpc_serverCall(req,**kwargs):
    return GnrCustomWebPage(req, **kwargs).serverCall()



Creating a sample application instance

We want to create an instance of an application composed only by one package, video. From the console in any directory the build command is gnrmakeinstance followed by the instance name and then by all the packages included by the instance:

 sudo gnrmkinstance videoapp video 

Now the directory videoapp /usr/local/genro/data/instances has been created. At the moment it only contains the file instanceconfig.xml and the empty folder data.

First of all, we need to configure the database line within the instanceconfig.xml:

You can use Postgres as DB:

<db implementation="postgres" host="localhost" password="mypassword" user="foo" dbname="videodb"/>

and Sqlite DB too:

<db implementation="sqlite" password="foo" user="bar" filename='data/videodb' dbname='videodb'/>

For this tutorial use the Sqlite implementation. Then we have to update the instance's database structure or, if empty, to create it by the execution, from the instance's directory (e.g.: /usr/local/genro/data/instances/videoapp), of the command:

 sudo gnrdbsetup

In this example let's populate the database importing data from a proper xml file:

 gnrdbsetup import /foo/bar/videodata.xml

Now the application instance is ready and can be eventually customized.

Creating a sample site

Now we want to create a site, starting from our brand-new application instance. To do this we use the command gnrmksite from the instance directory. The correct syntax for gnrmksite is:

gnrmksite sitepath [instancepath]

In this example we write:

 sudo gnrmksite /usr/local/genro/data/sites/myvideosite

The second argument, instancepath is optional, if it isn't passed the command adds to the site the current directory. This bin command prepares an empty site structure that contains all the instance's pages divided by packages.

Since a site can be multi-instance, if you apply the command gnrmksite to the same site but from a different instance, the instance is added to the site.

In the end, here is what we made

  • the package video
  • the application instance videoapp
  • the site myvideosite

Set your Server configuration

Now, before seeing what we have done, we have to place a symbolic link of the site folder into the htdocs. So from your htdocs you have to write in your console something like this:

 ln -s /usr/local/genro/data/sites/myvideosite myvideosite

Let's set the file httpd.conf in the dir /usr/local/apache2/conf adding this line at the end of the file:

<Directory /usr/local/apache2/htdocs/myvideosite/pages> 
SetHandler mod_python 
PythonHandler mod_python.publisher
PythonDebug On 
</Directory>

Now start your apache2 server:

 sudo /usr/local/apache2/bin/apachectl start

Go to your localhost address

http://localhost:8001/myvideosite/pages/video/movieinfo.py

Genro bin commands that we have used

commandarg 1arg 2description
gnrmkpackagepackagename Creates an empty package in the current directory
gnrmkinstanceinstance nameincluded packages Creates in genro/data/instances an empty instance that includes the passed packages
gnrdbsetup mode [check, import]if mode import [path of xml dump]Check if database structure corresponds to the model and if doesn't it updates the db structure. If mode is import it loads data from an xml dump
gnrmksitesitepath[instancepath] If the site doesn't exists yet, it creates the site, containing the current instance's pages else it adds the instance to the site

Attachments