Creating a Movie Database Application¶

In this tutorial we will create a fully functional movie database application with Camelot. We assume Camelot is properly installed. An all in one installer for Windows is available as an SDK to develop Camelot applications (Python SDK).

Setup Spyder¶ In this section, we will explain how to setup the Spyder IDE for developing a Camelot project. If you are not using Spyder, you can skip this and jump to the next section. Start ‣ All Programs ‣ Python SDK ‣ Spyder Within Spyder, open the Project Explorer : View ‣ Windows and toolbars ‣ Project explorer In the Project Explorer change the workspace directory, to the directory where you want to put your Camelot Projects. Next, still in the Project Explorer, right click to create a new project using : New Project Enter Videostore as the project name.

Starting a new Camelot project¶ We begin with the creation of a new Camelot project, using the camelot_admin tool : Start ‣ All Programs ‣ Python SDK ‣ New Camelot Application Note From the command prompt (or shell), go to the directory in which the new project should be created. Type the following command: python -m camelot.bin.camelot_admin A dialog appears where the basic information of the application can be filled in. Select the newly created Videostore directory as the location of the source code. Press OK to generate the source code of the project. The source code should now appear in the selected directory.

Main Window and Views¶ To run the application, double click on the main.py file in Spyder, which contains the entry point of your Camelot application and run this file. Run ‣ Run ‣ Ok Note From the command prompt, simply start the script python main.py your Qt GUI should look like the one we show in the picture below: The application has a customizable menu and toolbar, a left navigation pane, and a central area, where default the Home tab is opened, on which nothing is currently displayed. The navigation pane has its first section expanded. The navigation pane uses Sections to group Actions . Each button in the navigation pane represents a Section , and each entry of the navigation tree is an Action . Most standard Actions open a single table view of an Entity in a new tab. Notice that the application disables most of the menus and the toolbar buttons. When we open a table view, more options become available. Entities are opened in the active tab, unless they are opened by selecting Open in New Tab from the context menu (right click) of the entity link, which will obviously open a new tab to right. Tabs can be closed by clicking the X in the tab itself. Each row is a record with some fields that we can edit (others might not be editable). Let’s now add a new row by clicking on the new icon (icon farthest the the left in the toolbar above the navigation pane). We now see a new window, containing a form view with additional fields. Forms label required fields in bold. Fill in a first and last name, and close the form. Camelot will automatically validate and echo the changes to the database. We can reopen the form by clicking on the blue folder icon in the first column of each row of the table. Notice also that there is now an entry in our table. That’s it for basic usages of the interface. Next we will write code for our database model.

Creating the Movie Model¶ Let’s first take a look at the main.py in our project directory. It contains a my_settings object which is appended to the global settings . The Global settings object contains the global configuration for things such as database and file location. class MySettings ( SimpleSettings ): # add an ENGINE or a CAMELOT_MEDIA_ROOT method here to connect # to another database or change the location where files are stored # # def ENGINE( self ): # from sqlalchemy import create_engine # return create_engine( 'postgresql://user:passwd@127.0.0.1/database' ) def setup_model ( self ): """This function will be called at application startup, it is used to setup the model""" from camelot.core.sql import metadata from camelot.core.orm import setup_all metadata . bind = self . ENGINE () import camelot.model.authentication import camelot.model.i18n import camelot.model.memento import myapplication.model setup_all () metadata . create_all () my_settings = MySettings ( 'My Company' , 'My Application' ) settings . append ( my_settings ) Now we can look at model.py . Camelot has already imported some classes for us. They are used to create our entities. Let’s say we want a movie entity with a title , a short description , a release date , and a genre . The aforementioned specifications translate into the following Python code, that we add to our model.py module: from sqlalchemy import Unicode , Date from sqlalchemy.schema import Column from camelot.core.orm import Entity from camelot.admin.entity_admin import EntityAdmin class Movie ( Entity ): __tablename__ = 'movie' title = Column ( Unicode ( 60 ), nullable = False ) short_description = Column ( Unicode ( 512 ) ) release_date = Column ( Date () ) genre = Column ( Unicode ( 15 ) ) Note The complete source code of this tutorial can be found in the camelot_example folder of the Camelot source code. Movie inherits camelot.core.orm.Entity , which is the declarative base class for all objects that should be stored in the database. We use the __tablename__ attribute to to name the table ourselves in which the data will be stored, otherwise a default tablename would have been used. Our entity holds four fields that are stored in columns in the table. title = Column ( Unicode ( 60 ), nullable = False ) title holds up to 60 unicode characters, and cannot be left empty: short_description = Column ( Unicode ( 512 ) ) short_description can hold up to 512 characters: release_date = Column ( Date () ) genre = Column ( Unicode ( 15 ) ) release_date holds a date, and genre up to 15 unicode characters: For more information about defining models, refer to the SQLAlchemy Declarative extension. The different SQLAlchemy column types used are described here. Finally, custom Camelot fields are documented in the section camelot-column-types. Let’s now create an EntityAdmin subclass

The EntityAdmin Subclass¶ We have to tell Camelot about our entities, so they show up in the GUI . This is one of the purposes of camelot.admin.entity_admin.EntityAdmin subclasses. After adding the EntityAdmin subclass, our Movie class now looks like this: class Movie ( Entity ): __tablename__ = 'movie' title = Column ( Unicode ( 60 ), nullable = False ) short_description = Column ( Unicode ( 512 ) ) release_date = Column ( Date () ) genre = Column ( Unicode ( 15 ) ) def __unicode__ ( self ): return self . title or 'Untitled movie' class Admin ( EntityAdmin ): verbose_name = 'Movie' list_display = [ 'title' , 'short_description' , 'release_date' , 'genre' ] We made Admin an inner class to strengthen the link between it and the Entity subclass. Camelot does not force us. Assign your EntityAdmin class to the Admin Entity member to put it somewhere else. verbose_name will be the label used in navigation trees. The last attribute is interesting; it holds a list containing the fields we have defined above. As the name suggests, list_display tells Camelot to only show the fields specified in the list. list_display fields are also taken as the default fields to show on a form. In our case we want to display four fields: title , short_description , release_date , and genre (that is, all of them.) The fields displayed on the form can optionally be specified too in the form_display attribute. We also add a __unicode__() method that will return either the title of the movie entity or 'Untitled movie' if title is empty. The __unicode__() method will be called in case Camelot needs a textual representation of an object, such as in a window title. Let’s move onto the last piece of the puzzle.

Configuring the Application¶ We are now working with application_admin.py . One of the tasks of application_admin.py is to specify the sections in the left pane of the main window. The created application has a class, MyApplicationAdmin . This class is a subclass of camelot.admin.application_admin.ApplicationAdmin , which is used to control the overall look and feel of every Camelot application. To change sections in the left pane of the main window, simply overwrite the get_sections method, to return a list of the desired sections. By default this method contains: def get_sections ( self ): from camelot.model.memento import Memento from camelot.model.i18n import Translation return [ Section ( _ ( 'My classes' ), self , Icon ( 'tango/22x22/apps/system-users.png' ), items = [] ), Section ( _ ( 'Configuration' ), self , Icon ( 'tango/22x22/categories/preferences-system.png' ), items = [ Memento , Translation ] ) ] which will display two buttons in the navigation pane, labelled 'My classes' and 'Configurations' , with the specified icon next to each label. And yes, the order matters. We need to add a new section for our Movie entity, this is done by extending the list of sections returned by the get_sections method with a Movie section: from videostore.model import Movie return [ Section ( _ ( 'Movie' ), self , Icon ( 'tango/22x22/apps/system-users.png' ), items = [ Movie ] ), Section ( _ ( 'Configuration' ), self , Icon ( 'tango/22x22/categories/preferences-system.png' ), items = [ Memento , Translation ] ) ] The constructor of a section object takes the name of the section, a reference to the application admin object, the icon to be used and the items in the section. The items is a list of the entities for which a table view should shown. Camelot comes with the Tango icon collection; we use a suitable icon for our movie section. We can now try our application. We see a new button the navigation pane labelled ‘Movies’ . Clicking on it fills the navigation tree with the only entity in the movies’s section. Clicking on this tree entry opens the table view. And if we click on the blue folder of each record, a form view appears as shown below. That’s it for the basics of defining an entity and setting it for display in Camelot. Next we look at relationships between entities.