Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Web Development

1797 Articles
article-image-individual-learning-plan-ilp-moodle-19
Packt
28 May 2010
10 min read
Save for later

Individual Learning Plan (ILP) with Moodle 1.9

Packt
28 May 2010
10 min read
(For more resources on Moodle 1.9, see here.) The ILP module, once installed and activated, allows you to set some quite detailed targets within courses and to fine tune reports to and about students in order to better motivate them in their learning. This type of power means that there are quite a few options associated with the module and you will need to use the ones that are best suited to your needs. There is also the capability to tie the system in with your institution's own Student Information System (SIS) or Management Information System (MIS)) through a database abstraction layer. If you require this level of integration, you will need to discuss this with your network team or the company that provides your Moodle hosting service. In the UK, at least you can discuss this functionality with a Moodle partner that specializes in system integration with MIS. You can find out more about this at http://moodle.com/integration/. The installation process will install two modules: targets and reports, as well as a number of ILP related blocks for your courses such as Personal Learning Plan and Student Information. The modules and blocks that are installed as part of this package have a number of related settings associated with them, which will need to be adjusted at the site administration level. If you are the site administrator, you can do this; if not, you will need to ask the site admin to make the necessary changes. Module settings: Targets and Reports The basic settings required are to be able to set targets and view reports, though there are numerous levels and complexities to this activity. Again, you will need to adjust these as required. The settings are in the site administration panel. You will see two new icons for the ILP modules, as shown in the following screenshot, namely, Report and Target: Each of these new modules has a corresponding settings link. Report options The settings for the report allow you to determine what reports are visible to staff and students, as well as what can be shared between students. Set the visibility and information as required by your particular course or institution. The first block of settings relate to how the reports are viewed and whether or not students are made aware of any interactions on the part of tutors, as shown in the following screenshot: In this case, we are choosing to be able to see the status of each individual student and to send them messages when comments or concerns are posted. However, we have chosen not to show reports just within a course, as we are likely to teach students across the faculty. Therefore, it is more useful to get an overview of how they are working. The concerns we might highlight could be that a student has been missing key practical classes or has not attended their work placement. The second block of settings determines what types of reports you would like to see. It may be that you are only responsible for a certain aspect of a student's learning, in which case you may not enable all of the reporting functions. In this case, we are choosing to see all reports, as shown in the following screenshot. This may be the case if you are a personal tutor for some students and wish to get a detailed overview of their progress and activities, as well as be able to talk to them about any concerns raised by other staff. For example, a student to whom you are a personal tutor might express an interest in Product Design and therefore you might consult with colleagues in this subject area to set key targets for the student to achieve. These targets and achievements can be discussed with the students or with the students and their parents, to make sure that they are working towards their desired goals in technology. We can now save these settings in order to use all of these features on courses that we teach. Target options The settings for the Target module are similar—again the default for course-specific targets is disabled, which makes it easier to see student information across subjects. The main settings here, as shown in the following screenshot, relate to how messages are relayed to students about their targets. For example, there may be a modification to an exam board specification that makes a student's established target not such a high priority. If you are teaching students at a distance and do not see them regularly, then this would be a useful way to notify them of the changes. ILP blocks: Personal Learning Plan (PLP) The block element of ILP has several more settings that allow some customization of the block once initiated on your course page. It is shown under the add blocks menu as the Personal Learning Plan (PLP), showing that it is something that students have more ownership of as they can add targets and concerns themselves. Main options The default settings would be "No", but in this case, we would like the students to be able to see a complete range of information in relation to themselves and their courses in design technology. If the user guide link is set to 1, then it will show a link to the online guide for the module. This might be something to set up once everyone is comfortable with the use of the ILP. Student information block The final settings on the blocks page are for Student Info. The settings here allow you to customize messages and instructions for students in relation to the information they put in the PLP, such as information about themselves that only they or their teacher can see, or shared information that all other students will be able to see. The student can then use this space to fill in information about themselves, which will tie in with their targets and concerns and give a full picture of them for staff and even potential employers. The student's view of this becomes available through the course, though it will also link in through their profile. We will look at this in detail now. The following screenshot shows the student's view of the above settings when initiated: Once these settings under modules and blocks have been saved, staff can now create targets and modify reports, and students can get an overview of their work and learning, as we will see now. Creating targets The first task is to add some targets to your course for your students. The block will link to the area that displays the students so that you can see the targets, but the targets are added as activities. Switch on the edit function and choose a target for a section of your course where it is appropriate. This will be under the activities drop-down menu. The target requires a basic name and a summary of what it is for, as with all other activities. Once it is set, you can then make more specific targets for each student in the group by clicking on the target link from the front of the course. The following screenshot shows the target named Research Skills that we have created: Clicking on this link will open up a menu for all of your students. For each student, there is a link for targets and here you can add or modify targets for the students. Here you can see that a target has been set with a deadline of one month after it is set. You can add comments as it progresses, and the drop-down menu allows you to modify it so that it is either achieved (in which case when, or withdrawn as not achievable). The targets themselves can be general targets that need to be achieved across the range of the student's learning, or they can be tied specifically to a course by checking the Course related option checkbox, as shown in the following screenshot: You can also see that we have the option to tie it to courses that the student is taking. If you are a personal tutor, you can work across the subject range and apply a number of targets. All of these can have a specified deadline. You now need to allow students to see their plans. Accessing personal plans As a teacher, you need to switch on editing for your course. This makes the block visible on the bottom-right margin of your course (assuming that is where you added the block). Choose the Personal Learning Plan block. This will then be added to your course and can be moved to where it is most suited to your layout. The preceding screenshot is the view that you will see as a teacher and will allow you to see and comment on a student's targets and reports as needed, as well as export those reports. The students will have a more restricted view, as shown in the following screenshot: When students will click on the link My PLP, it will open the interface showing them their personal settings as well as any targets, concerns, or reports related to them. The more settings you have enabled on the admin section, the more they will see, so it is down to decide what information they can access. In this case, the student will be able to add some details about themselves for you and their class, but also see how they are faring in terms of targets. This can be used for tutorial sessions so that they can work on improving areas of perceived strengths or weaknesses. In terms of the targets that are set, they can interact with staff through comments so that a clear dialog can be established and hopefully issues can be picked up on as soon as possible. Once you hav e added various targets and worked with students through their concerns and those of other staff, you can then pull it all together through a report. The report can then be used to show their skills and aptitudes in their individual design areas and may show that they have a preference and an aptitude in one area such as resistant materials but not in food. This information can be used to provide clearer information for the students in the courses you design and the examples you use. Summary This article introduced you to a Personal Learning module which allows you and your students to set and evaluate targets and personal goals. This module will help your students reflect on their work and allow you to better guide them in their ideas and practices. Further resources on this subject: Moodle 1.9 Teaching Techniques [book] Moodle 1.9 Math [book] Moodle 1.9: Exploring Design Portfolios [article] Testing Students' Knowledge using Moodle Modules [article] Managing Student Work using Moodle: Part 1 [article] Managing Student Work using Moodle: Part 2 [article] Managing Student Work using Moodle: Part 3 [article]
Read more
  • 0
  • 0
  • 1316

article-image-installing-and-configuring-joomla-local-and-remote-servers
Packt
27 May 2010
8 min read
Save for later

Installing and Configuring Joomla! on Local and Remote Servers

Packt
27 May 2010
8 min read
Like every other endeavor in life, there are two ways of installing Joomla!—the easy way and the difficult way. In order to do it the difficult way, you will need to set up your server by yourself before you proceed with the installation. You have the choice of environment to use for your new installation: you may install directly to a live server or you can set up a test environment on your local computer. Minimum system requirements A fully-operational web server (preferably Apache) is required to successfully install and use Joomla!. You also need a database (preferably MySQL) and the server-side scripting language PHP, together with specific modules for MySQL, XML, and Zlib functionality, which are activated within PHP amongst others. Following are the minimum versions of these server components that are required: Software Minimum requirement Recommended Latest options Website PHP 4.3.10 4.4.7 5.x.series http://php.net MySQL 3.23.x or above   5.x series http://dev.mysql.com/downloads/mysql/5.0.html Apache 1.3 or above   2.2 series http://httpd.apache.org Installation on a local computer There are a number of ways to set up a test environment on your own local computer. Most time-pressed developers will install and configure directly onto a live server, but there are good reasons for running your application first on a local development server: Developing your application locally allows you to work on it even if you are not connected to the Internet. The experience that you gain from getting your local server running on a simple installation like WampServer for a machine running Windows, or MAMP for a Mac, will make it easier for you to understand server processes and databases. This knowledge will certainly pay off as you get deeper into Joomla!. The Web is constantly scanned and archived by various search engines, and so will everything that you put on the Web. This information will be around for quite a bit of time and you certainly don't want Google to display your inevitable learning mistakes for the world to see. Installation on WampServer WampServer2 enables you to run Apache, MySQL, and PHP on Windows, and is available for free. You can download it from http://www.wampserver.com. The WampServer2 package comes with the following components already configured to work together: Apache 2.2.11 MySQL 5.1.30 PHP 5.2.8 There are similar packages that already include Joomla! (such as DeveloperSide and WDE). However, note that these may not always have the latest secure version of Joomla!. Therefore, it is better to use WampServer2 and load it with the Joomla! version of your choice. WampServer2 is self-installing. Just double-click on the icon after you've unpacked your zipped download and follow the installation instructions. This gets your development environment ready in just a few minutes. Now let the fun begin! Installing Joomla! 1.5 on localhost Installing Joomla! on localhost can be remarkably straightforward: Download the latest stable release of Joomla!, and unzip the discernible Joomla! 1.5 folder. You will need to use a tool such as WinZip for Windows (http://www.winzip.com) to perform this task. Another free alternative to WinZip is IZArc (http://www.izarc.org/). Locate the directory in which WampServer2 is installed on your computer. This will usually be the root of your computer's main directory (usually C:) and in a folder named wamp. Open it, locate the www folder, and copy your Joomla! 1.5 folder into it. Name the Joomla! folder as per your preference. In the unlikely scenario that you will be installing only one Joomla! test site on your local machine, you may—just for the sake of living to a ripe old age—name it Joomla. Navigate to your computer desktop taskbar tray, click on the WampServer icon, and select the Start All Services option (if this has not yet been selected). Then open your browser and navigate to http://localhost. This will display the main WampServer2 interface and you will see your project, Joomla, listed under Your Projects. However, because Joomla! needs a database to run, you must create the database for our project. Click on the phpMyAdmin link. This will display another interface, this time for phpMyAdmin. Enter the name of your new database in the Create new database field. For the simple reason that we shouldn't live a complicated life, we have given this database the same name (Joomla) as our project and our installation folder. We are now ready to install Joomla!. Joomla! has an automated installation script that automatically populates database tables. The installation script will set the base URL, connect Joomla! to the database, and create tables in the database. Navigate to http://localhost/Joomla and start your installation. You will be presented with a step-by-step guide to the installation in the later pages. Page 1: Choose Language This page asks what language you want to use for the installation. We select English as the language of choice. Click on the Next button to continue with your installation. Page 2: Pre-installation Check Checks are made by the installation script on server configuration. If any of these items are not supported (marked as No), then your system does not meet the minimum requirements for the installation of Joomla!, and you should take the appropriate actions in order to correct the errors. Failing to do so could lead to your Joomla! installation not functioning properly. You are not likely to face this problem on your local installation, and if you do, it can be quickly fixed. Page 3: License The License page is just a page of legalese that the developers of Joomla! really think you must read. It tells you the conditions for use of the free software and also spells out liabilities. Primarily, if the Joomla! installation makes your computer to explode or you start acting funny after you are done with the installation, the suppliers of Joomla! will accept no liability. After correcting any host-specific errors and reading the license, you will be directed to the Database Configuration page. Page 4: Database Configuration On the Database Configuration page, you specify the database where Joomla! will store and retrieve data. Select the type of database from the drop-down list. This will generally be mysql. Also, enter the hostname of the database server that Joomla! will be installed on. This may not necessarily be the same as your web server, so check with your hosting provider if you are not sure. In the present case, it will be localhost. Now enter the MySQL username, password, and database name that you wish to use with Joomla!. These must already exist for the database that you are going to use. We have already determined this when we created the data base. Here are the values for our present project: Host Name: localhost Username: root (unless you have changed it) Password: Leave blank (unless you added a password when you set up your database) Database Name: Joomla (or whatever you have called yours) Table Prefix: If you are installing more than one instance of Joomla! in a single database, then give one of them a prefix (such as jos2_), or else the second instance will not install. Otherwise, you may safely ignore this. Click on the Next button to continue. Page 5: FTP Configuration You can safely omit this step and go on to the next page. But if you do decide to carry out this step, do take notice of the following requirements: As explained on this Joomla! installation page, due to file system permission restrictions on Linux and other Unix systems (and PHP Safe Mode restrictions), an FTP layer is used to handle fi le system manipulation and to enable Joomla! installers. You may enter an FTP username and password with access to the Joomla! root directory. This will be the FTP account that handles all of the file system operations when Joomla! requires FTP access to complete a task. However, for security reasons, if the option is available, you are advised to create a separate FTP user account with access to the Joomla! installation only and not to the entire web server. Page 6: Main Configuration This is where you define your site's public identity. The descriptions of the fields are as follows: Site Name: Enter the name of your Joomla! site. Your E-mail: This will be the e-mail address of the website Super Administrator. Admin Password: Enter a new password and then confirm it, in the appropriate fields. Along with the username admin, this will be the password that you will use to login to the Administrator Control Panel at the end of the installation. Install Sample Data: It is strongly recommended that new Joomla! users install the default sample data. To do this, select this option and click on the button, before proceeding to the next stage. Page 7: Finish That's all! Your installation success screen will be displayed. Congratulations, you are now on your way to becoming a Joomla! Guru. Once the installation script has successfully been completed and you have removed the installation folder, you will be directed to the Joomla! Administration login page—if you want to immediately perform administrative functions on your new site. Otherwise, clicking on the Site icon will direct you to the front page of your site showing all of the sample data—if you have loaded it. That is the most of what you need to know about installing Joomla!.
Read more
  • 0
  • 0
  • 2546

article-image-moodle-19-exploring-design-portfolios
Packt
27 May 2010
9 min read
Save for later

Moodle 1.9: Exploring Design Portfolios

Packt
27 May 2010
9 min read
(For more resources on Moodle 1.9, see here.) Exploring the Exabis portfolio The Exabis portfolio is a third-party add-on that can be placed in your courses to allow students to store and organize their work and allow them to share it with others, for example, external verifiers. The code can be downloaded from the Modules and plugins section at the Moodle website (http://moodle.org/mod/data/view.php?d=13&rid=1142&filter=1). Once the code has been installed, the site administrator will need to check the settings of the block for all users. Site-wide settings The first job, for an administrator, is to make sure the settings meet the institution's needs. These settings are available on the administration panel. You may need your site administrator to adjust these for you if you do not have these permissions. The following screenshot shows the two options available: The settings will be determined by what version you have installed on your system, and in this case, the options relate to how the portfolio looks. The key feature of recent portfolios is the ability to create views that are customized web pages. Most students will be familiar with this activity through social networking sites. Installing the Exabis block into a course To use the Exabis block, you first need to enable editing within the course you are responsible for. To do this, you need to click on the Turn editing on button, as shown in the following screenshot: This will change the view of your course, and a block will now be visible on the right-hand column to add further blocks to your course. The Add button, as shown in the previous screenshot, is a drop-down list and will list all available blocks in alphabetical order. You need to scroll down until you find the Exabis E-Portfolio listing and then click to add this block. Once the block has been added to your course area, you can make some more localized adjustments. In the staff view, there are three options. However, the two lower options merely point to different tabs on the same menu as the MyPortfolio link. Once you open the portfolio, you can see the layout of the block and the functions that it supports, as shown in the following screenshot: The personal information tab The first tab allows students to build up some personal information so that they have a sort of limited resume or CV. Once students click on the Information tab, they will see one button (Edit), which will open an edit window to allow them to add some notes and details. The Categories tab After students have entered some basic information about themselves, they need to organize their material. This is achieved initially by establishing some categories under which the information they gather can be structured. In this example, using the Product Design course, the student may need to create categories for each section they are working with. In the UK, for example, this would be: Materials and Components, Design and Market Influence, and Process and Manufacture. By clicking on the Categories tab, there will, as with the Information tab, be an edit button visible. Clicking on this button will open a window to create the required categories, as shown in the following screenshot: By clicking on the New button, as shown in the previous screenshot, the category will be created and you will then have the choice to add sub-categories or new categories as required. The layout of this edit window is as shown in the following screenshot: These can be further broken down into sub-categories that match the course specification. The process is the same as creating categories, and with each new category created, an additional field appears to add sub-categories, as seen in the previous screenshot. The resulting structure could look similar to the following screenshot, where each part of the specification has a corresponding category and sub-category. These categories will now be available in drop-down menus for the students to add various resources, such as files and notes, as shown in the following screenshot: In the previous screenshot, you can see that students have a drop-down box under Categories, which lists categories and sub-categories for them to link their resources too. Building up the portfolio content Students can now build up their portfolio of evidence and can share this information, if they need to, with staff, other students, or external examiners. The information is organized through the main My Portfolio tab, as shown in the following screenshot: Under this tab, there are sub-tabs that allow the students to link to websites, upload files, and also make notes about some of the material they have gathered. Each of these can now be associated with a category or sub-category to give some clear definition to their research work. The following screenshot shows a student adding some files to a sub-category related to design: In the previous screenshot, students could attach a file which may be some notes they made on a factory visit that they have scanned. Gradually, they can start building up a detailed folder of information and links to other useful resources. The following screenshot shows the MyPortfolio view as a student builds up some of their reference material and notes. Each of the resources is clearly categorized and time stamped and the type of resources is easy to see. Creating views In the release under discussion here (version 3.2.3 release 168) there is a tab to create views. This is still under development and not fully functional, but may well be functional by the time you install it. Clicking on the Views tab will show a button to add a view. Clicking on the Add View button will open an edit window to allow the student to organize their views, as shown in the following screenshot: The views are quite basic at present, but will allow students to build up a portfolio of evidence in an easy and organized way. Sharing their work and thoughts If students would like to share some of their work with each other, then they can via the Views tab. This tab, on the latest version, has a link to allow sharing. Once students enable the sharing function by clicking on the Change link, they can then choose what type of sharing they require and with whom. In the case shown here, the student can elect to share his/her work externally by creating a link to his/her folder from an external or an internal link. The Internal Access option allows them to further specify who can see their portfolio. In this case, they can share it with all of the staff who teach them in the design and technology faculty, or just some of the staff. In this case, when the product design teacher logs in and checks for shared portfolios, they will see this student's work. Importing and exporting portfolios Increasingly with e-portfolios there is the need to be able to take the entire portfolio with the students to other places of study or work. With the Exabis system, there is the ability to export the student's work in a number of formats. The two formats, currently available are Shareable Content Object Reference Module (SCORM) and Extensible Markup Language (XML). Both of these are file structures used to import and export groups of files from web-based systems such as Moodle. The import facility in Exabis will import a SCORM file, which is usually in a zipped format. The options shown for Export/Import are shown in the following screenshot: In both cases shown here, the export will allow students to save their work as a ZIP file, and depending on how they have structured their portfolio, they will have a range of choices regarding what to include in the export. The following screenshot shows the options for a SCORM export. The student, as shown in the previous screenshot, has chosen to save his/her Product Development material in a SCORM file. Clicking on the Create SCORM-File button will open a download dialog window where the student can chose where on his/her computer to save the zipped file. An additional feature shown in the previous Export your portfolio screenshot is the ability to include Moodle assignments in the portfolio of evidence. This would be useful if students take the portfolio to a new job. Clicking on the Import from Moodle-Assignments link results in a screen where students can add their assignments, as shown in the following screenshot: Under the Action column shown in this screenshot, the student can click on the add this file link. Clicking this link will open the MyPortfolio:Add window and the student can link this assignment to a category. The resulting link will then appear in their MyPortfolio: Files view. The assignment itself will be a hyperlink, which will open the word-processed assignment when clicked. Opening the assignment link will create a full URL to where the assignment can be located so that external examiners or employers can also view the work. It allows additional notes to be added by the student, such as follow up comments, as shown in the following screenshot: The additional commentary shows how the student has used the portfolio to track their learning process and to reflect on their earlier work. The whole process is therefore contained in an organized structure that the student controls and can be modified as their greater understanding dictates. Future developments in Exabis As mentioned, the views in this portfolio are not yet fully developed, but the current version is very usable. In order to have more flexibility and functionality, it is necessary to install a more fully featured e-portfolio such as MyStuff, which we will investigate in the next section.
Read more
  • 0
  • 0
  • 2487
Visually different images

article-image-building-news-aggregating-site-joomla
Packt
26 May 2010
3 min read
Save for later

Building a News Aggregating Site in Joomla!

Packt
26 May 2010
3 min read
(For more resources on Joomla!, see here.) The completed news aggregation site will look similar to the example shown in the following screenshot: Build Weird Hap'nins Vaughan Pyre is a very ambitious webpreneur. What he really hopes for is a website that is completely self-maintaining, and on which he can place some Google AdSense blocks. Clicks from the visitors to his site will ensure that he makes lots of money. For this, he needs a site where the content updates regularly with fresh content so that visitors will keep coming back to click on some more Google ads. Vaughan's ultimate objective is to create several of these websites. Template The template chosen is Midnight by BuyHTTP, which is a template that fits the theme of this unique website. Extensions This is, surprisingly, a very simple site to build, and much of the requirements can be actually be achieved by using the native News Feeds component. However, the News Feeds component will only list the title links to the external feed items, whereas what Vaughan wants is that the feeds are pulled into the site as articles. Therefore, we will be using an automatic article generator component. There are several of such components on the Joomla! extensions site, but almost all of them are commercial. Vaughan is a skinflint and will not pay to buy any script, so what we are looking for is free component. That is why we have chosen the following: 4RSS—aggregates RSS feeds and creates articles from them JCron Scheduler—used for cron jobs management and scheduling to simulate cron jobs through the Joomla! frontend interface at preset intervals Indeed, were it not for the fact that Vaughan needs the content to automatically be updated, we needn't use any extension other than the 4RSS component. Other extensions The core module that will be used for this site is: Main Menu module—creates the primary navigation functionality for the site pages Sections and categories New sections and categories will need to be created so that incoming article feeds will be correctly routed according to their description. A new section will be created that we will call Feed. Under this section, we shall have three categories—Bad News, More Bad News, and Weird News. Create a new section We intend to create a section that will be named Feed. In order to do this, perform the following steps: Navigate to the Section Manager from the Control Panel, and then click on the New icon at the top right-hand side, in order to create a new section. On the next page, add the name of the section, and then save your changes. Create new categories To create a new category, perform the following steps: Navigate to the Category Manager page from the Control Panel. On the following page, create a new category in the same way as we created the new section. However, remember to set the Section to Feed.
Read more
  • 0
  • 0
  • 2558

article-image-plone-3-themes
Packt
26 May 2010
9 min read
Save for later

Plone 3 Themes

Packt
26 May 2010
9 min read
(For more resources on Plone, see here.) Plone's stock configuration delivers a great deal of concrete functionality: workflow, security, tagging, and more. However, the people whom you need to win over—like your boss and the public—often form their first impressions of your site based solely on visual design. Replacing the out-of-the-box look of Plone with one tailored to your organization is thus a very important task. Changing the overall look of a Plone site requires more than just the web designer's usual toolkit of HTML and CSS. In this article, we provide an introduction to the additional Zope- and Plone-specific techniques you need. We give an overview of Plone's somewhat complicated theming situation, show how to theme a site in a portable, reusable way, and demonstrate practices that strike a balance among ease, speed, and compatibility with future versions of Plone. Theming is a complex topic, and there are entire books on that topic alone, so we also give plenty of outside references in case your needs extend beyond the basic. An overview of Plone theming Plone themes, also known as skins, are visual designs that can be applied to a site, independent of its content. There are two main ways to create a theme: through the web and via the filesystem. Through-the-web versus filesystem One of the great advantages of Zope (and thus Plone) has historically been the customization power available through its web-based interface. Though there are some holes in this functionality with Plone 3 and 4, you can, for the most part, still point and click your way to a working theme. The advantages of this approach are: Immediate feedback. Iterations are simple. As a result, you're encouraged to test often, bugs turn up early, and bugs caught early are bugs solved easily. Explorability. Though the Zope Management Interface, where most theme work takes place, isn't the best-organized or friendliest environment in the world, it at least offers some semblance of navigable structure. You can find a piece of HTML or CSS you want to customize, click a button, and begin editing. There's less need to think abstractly. Accessibility. Through-the-web theming requires no access to the server's filesystem, so it is usable by people without, for example, Unix command-line experience or the ability to restart Zope. The alternative is theming by developing add-on products, which live on the server's filesystem. The advantages of this are: Better tools. Expressing a theme as files and folders lets you use the entire ecosystem of filesystem-based development tools: proper text editors and version control systems, for example. Ease of re-use. Encapsulating a theme as a product means you can easily make use of it on more than one site, copy it from machine to machine, or share it with the world. Completeness. Some customizations can't yet be done through the Web: for example, moving the search box from the top of the page to the bottom by moving its viewlet into a different viewlet manager. In practice, a filesystem product is usually better, with through-the-web styling used to test changes and to make emergency in-production tweaks between Zope restarts. A load of languages Theming involves several special-purpose languages. Here's the rundown: Language Use in Theming HTML The old standby, Hypertext Markup Language defines the semantic structure of every page. Plone's markup sticks admirably to specifying meaning and avoids visual design. For example, its navigation bars are <ul>s, and its portlets (those omnipresent titled sidebars) are actually definition lists (<dl>s) with the title as the term and the content as the definition. Visual styling is applied almost wholly by CSS. CSS Cascading Stylesheets, another standard tool in the web designer's kit, apply a layer of visual design atop HTML. Because Plone's HTML so assiduously avoids visual design, we can change the look of a Plone site substantially without tampering with markup. TAL Most theming can be done with just CSS, but sometimes, like when adding new element to a page, only HTML changes will do. All HTML in Plone is produced by Template Attribute Language (TAL), a simple XML-based language so named because it nestles entirely within the attributes of XML tags. Like other templating languages, TAL is a more readable alternative to littering program code with bits of hard-coded markup. It is good for inserting content into a page skeleton, repeating portions of a page, and doing other simple presentation logic. More complicated logic is best done in Python modules, where you aren't limited to cramped one-liners. A good introduction to TAL is http://docs.zope.org/zope2/zope2book/ZPT.html. METAL The Macro Expansion for TAL (METAL) language helps combine bits of TAL from different templates to create a single page. http://docs.zope.org/zope2/zope2book/ZPT.html#macros is a good introduction. Python The general-purpose language Zope and Plone are written in. We will write almost no Python in this article, but it often does make an appearance in page templates. It has a much more prominent role in Zope 3-style theming than in Zope 2. ZCML Some parts of theming use the Zope 3 component architecture, a scheme for tying plugins and customizations into a large system like Plone. The Zope Component Markup Language (ZCML) is an XML-based language that specifies where to plug these in. For example, we will use ZCML to tie our theme product to a third-party package that drastically simplifies overriding some templates. GenericSetup XML A variety of XML mini-languages, which show up in your product's profiles folder. These are run by GenericSetup, Plone's installation framework, when your theme product is installed or uninstalled. Don't let theming hold you up Theming is complicated and can be time-consuming the first time through. Don't make the common mistake of letting it hold up work on the rest of your site. Indeed, most information-oriented work—audience analysis, the creation and input of content, information architecture decisions, and development of custom content types—can go on without much thought toward the coat of paint that will eventually go over it. (Likewise, you can change the look of your site later without having to redo all your navigation and content.) The few elements to decide on ahead of time are… Navigation. What is your navigation strategy? Should the theme provide space for main or contextual navigation or for a search field? It can help to have your graphic designer join you for the last few minutes of each information architecture discussion to synchronize expectations. Drawing wireframes is another fast way to get everybody on the same page. For an excellent primer on strategies for organizing your site's content, see Peter Morville's Information Architecture for the World Wide Web. CSS styles. The style menu in Plone's built-in editor is commonly customized to suit the semantic needs of the site at hand. Decide early in the design process what styles will be needed: for example, body text, warning messages, sidebars containing supplementary material, and various levels of headings. It's not necessary to settle on a look for these styles—just to enumerate them and establish their CSS class names. After that, theme and content work can progress in parallel. Prepare your development environment Before we get down the business of creating a theme, make sure you have all the tools and settings in place: Run Zope in foreground mode. When developing, always launch Zope using bin/instance fg rather than bin/instance start. At the cost of a little processor power, this greatly speeds development by… Puting Zope into debug mode. This means it will notice certain changes to the product we're developing without needing to be constantly restarted. In Plone 3.3 and above, this automatically turns on the CSS and JavaScript debug modes as well (explained below). Printing error messages, usually hidden in the event.log file, to the terminal. Plone typically makes a lot of noise when it starts up; that can be ignored. But watch for errors, hidden among the innocuous INFO and DEBUG messages, when you exercise the functionality of your product. Turn on CSS debug mode. With Plone 3.3 or above, you can skip this step, as it's implicitly done when you run Zope in foreground mode. In older versions of Plone, go into the ZMI, then to your Plone site, and finally to portal_css. There, turn on Debug/development mode. This will keep Plone from doing its clever caching, merging, and compression of stylesheets while you're developing them, helping ensure that you always see the latest version of your work. Without CSS debug mode, your CSS changes will take effect only when Zope is restarted. Get Firefox, Firebug, and the Web Developer add-on. Firefox is a nice browser, but what really makes it shine is its third-party plugins. Get the latest version, available from http://www.getfirefox.com/, then grab two vital plugins, Firebug (http://getfirebug.com/) and Web Developer (https://addons.mozilla.org/firefox/addon/60). Turn off caching. In Firefox, show the Web Developer Toolbar (View ? Toolbars ? Web Developer Toolbar), then pull down its Disable menu and select Disable Cache. Together with enabling CSS debug mode, this will ensure that you always see your latest CSS changes. Nothing is more frustrating than spending hours chasing a problem, only to track it down to a stale cache. If you use Firefox for casual browsing, you may not wish to disable caching globally and slow down your surfing. In that case, be sure to use Shift+Command+R (on the Mac) or Shift+Ctrl+R (on other platforms) to force your stylesheets to reload when doing theme work. Begin your theme On-disk theme products can be quite verbose, so we employ a program to generate the skeleton of ours. We'll then make a few clean-ups before moving on to making a visual impact. Install paster and ZopeSkel To generate the empty shell of a theme, we'll use a code generation tool called paster. A set of Zope- and Plone-specific code snippets, called ZopeSkel, extends paster to provide a sort of "madlibs for Plone", churning out skeletal products whose blanks we can fill in. Here's how to get a copy of paster up and running: Some installations of Plone come with paster and ZopeSkel; check the bin folder in your buildout. If paster is in there, you're done; skip to the next section. If not, read on. Install easy_install, a simple Python installer, which we can use to install paster and ZopeSkel. Follow the platform-specific instructions on the easy_install download page: http://pypi.python.org/ pypi/setuptools. Use easy_install to install ZopeSkel, which also automatically installs paster. For example: easy_install ZopeSkel
Read more
  • 0
  • 0
  • 1727

article-image-creating-installing-and-tweaking-your-theme-using-plone-3
Packt
26 May 2010
12 min read
Save for later

Creating, Installing and Tweaking your theme using Plone 3

Packt
26 May 2010
12 min read
(For more resources on Plone here.) We will first inspect a few structural changes and install them, and then finally examine the various components and skin layer items that have been changed, one at a time. Where restarting Zope or rerunning your buildout would be required, this will be noted. About the theme This theme and its design are available for personal and professional use to anyone, and can be freely modified. You can (and should) download the files from https://svn.plone.org/svn/collective/plonetheme.guria/trunk using the following command: svn co https://svn.plone.org/svn/collective/plonetheme.guria/trunk plonetheme.guria Note the space between the words trunk and plonetheme.guria. This theme is intended for installation on Plone 3 web sites. The finished theme should look like the following, but we have work to do to make this happen: This theme was created by me, for use by a charity group in India, called Guria (http://www.guriaindia.org), dedicated to ending human trafficking and prostitution. The finished site is currently in development, and is generously hosted free of charge by the talented folks at Six Feet Up (sixfeetup.com). Additionally, most of the code and lessons learned come courtesy of similar themes created by the staff at ONE/Northwest in Seattle, Washington. The design for this theme was created with the assumption that most of the tasks would need to be present in this theme. In fact, the only task not covered here is the creation of a new viewlet manager. Creation of viewlet managers is discussed at http://plone.org/documentation/how-to/adding-portlet-managers and http://plone.org/documentation/manual/theme-reference/elements/viewletmanager/override. Creating a theme product I created a theme product named plonetheme.guria, using the command line syntax paster create –t plone3_theme, while we were located in the src/ directory of our buildout, as seen next: [bash: /opt/mybuildout/src] paster create -t plone3_theme plonetheme.guriaSelected and implied templates: ZopeSkel#basic_namespace A project with a namespace package ZopeSkel#plone A Plone project ZopeSkel#plone3_theme A Theme for Plone 3.0Variables: egg: plonetheme.guria package: plonethemeguria project: plonetheme.guriaEnter namespace_package (Namespace package (like plonetheme)) ['plonetheme']:Enter package (The package contained namespace package (like example)) ['example']: guriaEnter skinname (The skin selection to be added to 'portal_skins' (like 'My Theme')) ['']: Guria Theme for the Plone Theming BookEnter skinbase (Name of the skin selection from which the new one will be copied) ['Plone Default']:Enter empty_styles (Override default public stylesheets with empty ones?) [True]: FalseEnter include_doc (Include in-line documentation in generated code?) [False]:Enter zope2product (Are you creating a Zope 2 Product?) [True]:Enter version (Version) ['0.1']:Enter description (One-line description of the package) ['An installable theme for Plone 3.0']:Enter long_description (Multi-line description (in reST)) ['']:Enter author (Author name) ['Plone Collective']: Veda WilliamsEnter author_email (Author email) ['product-developers@lists. plone.org']: [email protected] keywords (Space-separated keywords/tags) ['web zope plone theme']:Enter url (URL of homepage) ['http://svn.plone.org/svn/collective/']:Enter license_name (License name) ['GPL']:Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:Creating template basic_namespaceCreating directory ./plonetheme.guria[snip] You may wish to generate a new Plone theme product yourself, so that you can compare and contrast the differences between the Guria theme and a vanilla Plone theme. Notice that the full name of the theme is plonetheme.guria, and where an item shows as blank, it defaults to the example value in that step. In other words, the namespace package defaults to plonetheme, because there was no reason to change it. The skinname is set to a single lowercase word out of stylistic preference. It's important to also note that you should not use hyphens or spaces in your theme names, as they will not be recognized by your buildout. We've chosen not to override Plone's default stylesheets, and instead, we want to build on top of Plone's default (and excellent!) stylesheets. I prefer this method mostly because the layout needed for Plone's Contents view and other complex structural pieces are already taken care of by Plone's base stylesheets. It's easier than trying to rebuild those from scratch every time, but this is merely a personal preference. Following the creation of the theme, we register the theme product in our buildout.cfg, using the following syntax [buildout] ...develop = src/plonetheme.guria...[instance]eggs = plonetheme.guria...zcml = plonetheme.guria... If we were using the eggtractor egg, there would be no need to add these lines of code to our buildout.cfg; all we would need to do is rebuild our buildout and it would automatically recognize the new egg. eggtractor can be found at http://pypi.python.org/pypi/buildout.eggtractor, and is documented thoroughly. Assuming we are not using eggtractor, we must rebuild our buildout, as we have altered ZCML code and added a new egg: [bash: /opt/mybuildout/src/] ./bin/buildout This would be a good time to check your vanilla theme product into Subversion, so that you can track back to the original version, if needed. However, since this is an existing theme, there is no need to do so. For the purposes of following along, it might be best if you do not yet install the theme. We want to make some changes first. However, we will point out some caveats along the way, in case you installed the theme prematurely. Altering the theme product's structure Several modifications have been made to the theme product's structure to shorten folder names and change the default behavior. Again, this is mostly a personal preference. Let's take a look at these changes and how they were achieved. Renaming the theme In our theme product, you will see a file named profiles.zcml, located at mybuildout/src/plonetheme.guria/plonetheme/guria/profiles.zcml. The code looks like this: <configure i18n_domain="plonetheme.guria"> <genericsetup:registerProfile name="default" title="Guria Theme for the Plone Theming Book" directory="profiles/default" description='Extension profile for the "Guria Theme for the Plone Theming Book" Plone theme.' provides="Products.GenericSetup.interfaces.EXTENSION" /></configure> If you named your theme in a way that was less descriptive, you could alter the title. Naming your theme product properly is important, because you may have different types of products used for a given web site—for example, a policy product for content that might be used in tandem with your theme product. This text is what you see in the portal_quickinstaller at http://localhost:8080/mysite/portal_quickinstaller/manage_installProductsForm, where mysite is the name of your Plone site. You can also see this name if you install your theme product via Site Setup Add-on Products|, found at http://localhost:8080/mysite/prefs_install_products_form. If you change your XML here, and your theme product is already installed, you'll need to start (or restart) your Zope instance, using: [bash: /opt/mybuildout] ./bin/instance fg Shortening folder names Next, we look at the folder structure of our theme product. The standard Plone 3 theme produces folders with names like plonetheme_guria_custom_images, plonetheme_guria_custom_templates, and plonetheme_guria_styles. While there is nothing wrong with keeping this structure, it can be cumbersome to type or tab through (especially when checking items into Subversion). However, you might want to keep the existing folder names to help you distinguish which items of base Plone you modified. This can make migrations easier. If you choose this route, you probably want to create additional folders for non-base-Plone items. I personally prefer the shorter folder names and don't worry too much about the migration issues. In the case of this theme product, I opted to make the folder names shorter. First, I altered the names of the folders in the skins/ folder to guria_images, guria_styles, and guria_templates. Then, in the theme, go to mybuildout/plonetheme.guria/plonetheme/guria/skins.zcml. The code in this file is altered to appear as follows: <configure i18n_domain="plonetheme.guria"> <!-- File System Directory Views registration --> <cmf:registerDirectory name="guria_images"/> <cmf:registerDirectory name="guria_templates"/> <cmf:registerDirectory name="guria_styles"/></configure> One more step is required here. In plonetheme.guria/plonetheme/guria/profiles/default/skins.xml, the code is changed to read as follows: <?xml version="1.0"?><object name="portal_skins" allow_any="False" cookie_persistence="False" default_skin=" Guria Theme for the Plone Theming Book "> <object name="guria_images" meta_type="Filesystem Directory View" directory="plonetheme.guria:skins/guria_images"/> <object name="guria_templates" meta_type="Filesystem Directory View" directory="plonetheme.guria:skins/guria_templates"/> <object name="guria_styles" meta_type="Filesystem Directory View" directory="plonetheme.guria:skins/guria_styles"/> <skin-path name=" Guria Theme for the Plone Theming Book " based- on="Plone Default"> <layer name="guria_images" insert-after="custom"/> <layer name="guria_templates" insert-after="guria_images"/> <layer name="guria_styles" insert-after="guria_templates"/> </skin-path></object> Basically, the steps are the following:   Rename the folders on the filesystem. Modify the skins.zcml file to change the name of the filesystem directory view (what you see in the portal_skins/properties area of the ZMI). Modify the skins.xml file in the profiles/default folder to match. This alters the basic profile of your theme product. If you wanted to add additional folders and filesystem directory views here (a scripts/ folder, for example), you'd just add code by following the conventions given to you in these files and then create additional folders. Making changes to the ZCML file means that you would need to do a restart of your Zope instance. If you installed your theme product before making the changes to the skin layer names, you might want to inspect the skin layers at http://localhost:8080/mysite/ portal_skins/manage_propertiesForm, to make sure that the correct skin layers are listed. You might even need to reimport the "skins tool" step via portal_setup at http://localhost:8080/mysite/portal_setup/manage_importSteps. Make sure you choose the correct profile first by choosing your theme product's name from the drop-down list at the top of the import page. The theme product's name is the same name as you find in your profiles.zcml file. Adjusting how stylesheets and images are used Next, we remove some of the default behavior given to us by the plone3_theme recipe. In a vanilla theme product, folders named images/ and stylesheets/ are inserted into the plonetheme.guria/plonetheme/guria/browser/ directory. Additionally, a file named main.css is included in the stylesheets/ directory. I chose not to place the theme's images or stylesheets in the browser/ directory, as this is generally unnecessary for most themes. Advanced programmers may wish to expose these items to the browser layer, but this is generally a personal choice and carries with it additional consequences. I deleted the folders mentioned above, as well as the i file. Then, I opened the file named configure.zcml, located at plonetheme.guria/plonetheme/guria/browser/, and removed all of the following boilerplate text: <!-- Viewlets registration --> <!-- Zope 3 browser resources --> <!-- Resource directory for images --> <browser:resourceDirectory name="plonetheme.guria.images" directory="images" layer=".interfaces.IThemeSpecific" /> <!-- Resource directory for stylesheets --> <browser:resourceDirectory name="plonetheme.guria.stylesheets" directory="stylesheets" layer=".interfaces.IThemeSpecific" /> I then removed the highlighted code below fromI then removed the highlighted code below from plonetheme.guria/plonetheme/guria/profiles/default/cssregistry.xml:: <stylesheet title="" id="++resource++plonetheme.guria.stylesheets/main.css" media="screen" rel="stylesheet" rendering="import" cacheable="True" compression="safe" cookable="True" enabled="1" expression=""/> And replaced it with the following: <stylesheet title="" id="guria.css" media="screen" rel="stylesheet" rendering="import" cacheable="True" compression="safe" cookable="True" enabled="1" expression=""/> This, in effect, tells our theme product that we will be using a stylesheet named guria.css (or more correctly, guria.css.dtml, as we'll see in a moment). This stylesheet does not yet exist, so we have to create it. I wanted the option of making use of the DTML behavior provided by Plone, so that I could use certain base properties provided to us via the base_properties.props file (also located in our skins/guria_styles/ folder). DTML essentially allows us to use property-sheet variables and apply changes on a more global scale. The easiest way to create this new stylesheet is to go to your mybuildout/buildout-cache/eggs/Plone[some version number]/Products/CMFPlone/skins/plone_styles/ploneCustom.css and copy the contents of that file into a new stylesheet (named guria.css.dtml) in your theme's guria_styles/ folder (located in the skins/ directory at mybuildout/plonetheme.guria/plonetheme/guria/skins/guria_styles). The important bits of code you want are as follows: /* <dtml-with base_properties> (do not remove this :) *//* <dtml-call "REQUEST.set('portal_url', portal_url())"> (not this either :) *//* DELETE THIS LINE AND PUT YOUR CUSTOM STUFF HERE */ /* </dtml-with> */ Again, we would need to restart our Zope at this point, as we have modified our ZCML. If we had already installed our theme product, we'd also have to import our cssregistry.xml file via portal_setup in the ZMI, to capture the new GenericSetup profile settings. However, we have not yet installed the product, so we do not need to worry about this.
Read more
  • 0
  • 0
  • 1365
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €14.99/month. Cancel anytime
article-image-scaling-your-application-across-nodes-spring-pythons-remoting
Packt
24 May 2010
5 min read
Save for later

Scaling your Application Across Nodes with Spring Python's Remoting

Packt
24 May 2010
5 min read
(For more resources on Spring, see here.) With the explosion of the Internet into e-commerce in recent years, companies are under pressure to support lots of simultaneous customers. With users wanting richer interfaces that perform more business functions, this constantly leads to a need for more computing power than ever before, regardless of being web-based or thick-client. Seeing the slowdown of growth in total CPU horsepower, people are looking to multi-core CPUs, 64-bit chips, or at adding more servers to their enterprise in order to meet their growing needs. Developers face the challenge of designing applications in the simple environment of a desktop scaled back for cost savings. Then they must be able to deploy into multi-core, multi-server environments in order to meet their companies business demands. Different technologies have been developed in order to support this. Different protocols have been drafted to help communicate between nodes. The debate rages on whether talking across the network should be visible in the API or abstracted away. Different technologies to support remotely connecting client process with server processes is under constant development. Introduction to Pyro (Python Remote Objects) Pyro is an open source project (pyro.sourceforge.net) that provides an object oriented form of RPC. As stated on the project's site, it resembles Java's Remote Method Invocation (RMI). It is less similar to CORBA (http://www.corba.org), a technology-neutral wire protocol used to link multiple processes together, because it doesn't require an interface definition language, nor is oriented towards linking different languages together. Pyro supports Python-to-Python communications. Thanks to the power of Jython, it is easy to link Java-to-Python, and vice versa. Python Remote Objects is not to be confused with the Python Robotics open source project (also named Pyro). Pyro is very easy to use out of the box with existing Python applications. The ability to publish services isn't hard to add to existing applications. Pyro uses its own protocol for RPC communication. Fundamentally, a Pyro-based application involves launching a Pyro daemon thread and then registering your server component with this thread. From that point on, the thread along with your server code is in stand-by mode, waiting to process client calls. The next step involves creating a Pyro client proxy that is configured to find the daemon thread, and then forward client calls to the server. From a high level perspective, this is very similar to what Java RMI and CORBA offer. However, thanks to the dynamic nature of Python, the configuration steps are much easier, and there are no requirements to extend any classes or implement any interfaces.. As simple as it is to use Pyro, there is still the requirement to write some minimal code to instantiate your objects and then register them. You must also code up the clients, making them aware of Pyro as well. Since the intent of this article is to dive into using Spring Python, we will skip writing a pure Pyro application. Instead, let's see how to use Spring Python's out-of-the-box Pyro-based components, eliminating the need to write any Pyro glue code. This lets us delegate everything to our IoC container so that it can do all the integration steps by itself. This reduces the cost of making our application distributed to zero. Converting a simple application into a distributed one on the same machine For this example, let's develop a simple service that processes some data and produces a response. Then, we'll convert it to a distributed service. First, let's create a simple service. For this example, let's create one that returns us an array of strings representing the Happy Birthday song with someone's name embedded in it. class Service(object): def happy_birthday(self, name): results = [] for i in range(4): if i == 2: results.append("Happy Birthday Dear %s!" % name) else: results.append("Happy Birthday to you!") return results Our service isn't too elaborate. Instead of printing the data directly to screen, it collects it together and returns it to the caller. This allows us the caller to print it, test it, store it, or do whatever it wants with the result. In the following screen text, we see a simple client taking the results and printing them a little formatting inside the Python shell. As we can see, we have defined a simple service, and can call it directly. In our case, we are simply joining the list together with a newline character, and printing it to the screen. Fetching the service from an IoC container from springpython.config import *from simple_service import *class HappyBirthdayContext(PythonConfig): def __init__(self): PythonConfig.__init__(self) @Object def service(self): return Service() Creating a client to call the service Now let's write a client script that will create an instance of this IoC container, fetch the service, and use it. from springpython.context import *from simple_service_ctx import *if __name__ == "__main__": ctx = ApplicationContext(HappyBirthdayContext()) s = ctx.get_object("service") print "n".join(s.happy_birthday("Greg")) Running this client script neatly creates an instance of our IoC container, fetches the service, and calls it with the same arguments shown earlier.
Read more
  • 0
  • 0
  • 2038

article-image-easily-writing-sql-queries-spring-python
Packt
24 May 2010
9 min read
Save for later

Easily Writing SQL Queries with Spring Python

Packt
24 May 2010
9 min read
(For more resources on Spring, see here.) Many of our applications contain dynamic data that needs to be pulled from and stored within a relational database. Even though key/value based data stores exist, a huge majority of data stores in production are housed in a SQL-based relational database. Given this de facto requirement, it improves developer efficiency if we can focus on the SQL queries themselves, and not spend lots of time writing plumbing code and making every query fault tolerant. The classic SQL issue SQL is a long existing standard that shares a common paradigm for writing queries with many modern programming languages (including Python). The resulting effect is that coding queries by hand is laborious. Let's explore this dilemma by writing a simple SQL query using Python's database API. SQL is a long existing standard that shares a common paradigm for writing queries with many modern programming languages (including Python). The resulting effect is that coding queries by hand is laborious. Let's explore this dilemma by writing a simple SQL query using Python's database API. DROP TABLE IF EXISTS article;CREATE TABLE article ( id serial PRIMARY KEY, title VARCHAR(11), wiki_text VARCHAR(10000));INSERT INTO article(id, title, wiki_textVALUES(1, 'Spring Python Book', 'Welcome to the [http://springpythonbook.com Spring Python] book, where you can learn more about [[Spring Python]].');INSERT INTO article(id, title, wiki_textVALUES(2, 'Spring Python', ''''Spring Python''' takes the concepts of Spring and applies them to world of [http://python.org Python].'); Now, let's write a SQL statement that counts the number of wiki articles in the system using the database's shell. SELECT COUNT(*) FROM ARTICLE Now let's write some Python code that will run the same query on an sqlite3 database using Python's official database API (http://www.python.org/dev/peps/pep-0249). import sqlite3db = sqlite3.connect("/path/to/sqlite3db")cursor = db.cursor()results = Nonetry: try: cursor.execute("SELECT COUNT(*) FROM ARTICLE") results = cursor.fetchall() except Exception, e: print "execute: Trapped %s" % efinally: try: cursor.close() except Exception, e: print "close: Trapped %s, and throwing away" % ereturn results[0][0] That is a considerable block of code to execute such a simple query. Let's examine it in closer detail. First, we connect to the database. For sqlite3, all we needed was a path. Other database engines usually require a username and a password. Next, we create a cursor in which to hold our result set. Then we execute the query. To protect ourselves from any exceptions, we need to wrap this with some exception handlers. After completing the query, we fetch the results. After pulling the results from the result set into a variable, we close the cursor. Finally, we can return our response. Python bundles up the results into an array of tuples. Since we only need one row, and the first column, we do a double index lookup. What is all this code trying to find in the database? The key statement is in a single line. cursor.execute("SELECT COUNT(*) FROM ARTICLE") What if we were writing a script? This would be a lot of work to find one piece of information. Granted, a script that exits quickly could probably skip some of the error handling as well as closing the cursor. But it is still is quite a bit of boiler plate to just get a cursor for running a query. But what if this is part of a long running application? We need to close the cursors after every query to avoid leaking database resources. Large applications also have a lot of different queries we need to maintain. Coding this pattern over and over can sap a development team of its energy. Parameterizing the code This boiler plate block of code is a recurring pattern. Do you think we could parameterize it and make it reusable? We've already identified that the key piece of the SQL statement. Let's try and rewrite it as a function doing just that. import sqlite3def query(sql_statement): db = sqlite3.connect("/path/to/sqlite3db") cursor = db.cursor() results = None try: try: cursor.execute(sql_statement) results = cursor.fetchall() except Exception, e: print "execute: Trapped %s" % efinally: try: cursor.close() except Exception, e: print "close: Trapped %s, and throwing away" % ereturn results[0][0] Our first step nicely parameterizes the SQL statement, but that is not enough. The return statement is hard coded to return the first entry of the first row. For counting articles, what we have written its fine. But this isn't flexible enough for other queries. We need the ability to plug in our own results handler. import sqlite3def query(sql_statement, row_handler): db = sqlite3.connect("/path/to/sqlite3db") cursor = db.cursor() results = None try: try: cursor.execute(sql_statement) results = cursor.fetchall() except Exception, e: print "execute: Trapped %s" % e finally: try: cursor.close() except Exception, e: print "close: Trapped %s, and throwing away" % e return row_handler(results) We can now code a custom handler. def count_handler(results): return results[0][0]query("select COUNT(*) from ARTICLES", count_handler) With this custom results handler, we can now invoke our query function, and feed it both the query and the handler. The only thing left is to handle creating a connection to the database. It is left as an exercise for the reader to wrap the sqlite3 connection code with a factory solution. What we have coded here is essentially the core functionality of DatabaseTemplate. This method of taking an algorithm and parameterizing it for reuse is known as the template pattern. There are some extra checks done to protect the query from SQL injection attacks. Replacing multiple lines of query code with one line of Spring Python Spring Python has a convenient utility class called DatabaseTemplate that greatly simplifies this problem. Let's replace the two lines of import and connect code from the earlier example with some Spring Python setup code. from springpython.database.factory import Sqlite3ConnectionFactoryfrom springpython.database.core import DatabaseTemplateconn_factory = Sqlite3ConnectionFactory("/path/to/sqlite3db")dt = DatabaseTemplate(conn_factory) At first glance, we appear to be taking a step back. We just replaced two lines of earlier code with four lines. However, the next block should improve things significantly. Let's replace the earlier coded query with a call using our instance of return dt.query_for_object("SELECT COUNT(*) FROM ARTICLE") Now we have managed to reduce a complex 14-line block of code into one line of Spring Python code. This makes our Python code appear as simple as the original SQL statement we typed in the database's shell. And it also reduces the noise. The Spring triangle—Portable Service Abstractions From this diagram earlier , as an illustration of the key principles behind Spring Python is being made. The DatabaseTemplate represents a Portable Service Abstraction because: It is portable because it uses Python's standardized API, not tying us to any database vendor. Instead, in our example, we injected in an instance of Sqlite3ConnectionFactory It provides the useful service of easily accessing information stored in a relational database, but letting us focus on the query, not the plumbing code It offers a nice abstraction over Python's low level database API with reduced code noise. This allows us to avoid the cost and risk of writing code to manage cursors and exception handling DatabaseTemplate handles exceptions by catching and holding them, then properly closing the cursor. It then raises it wrapped inside a Spring Python DataAccessException. This way, database resources are properly disposed of without losing the exception stack trace. Using DatabaseTemplate to retrieve objects Our first example showed how we can easily reduce our code volume. But it was really only for a simple case. A really useful operation would be to execute a query, and transform the results into a list of objects. First, let's define a simple object we want to populate with the information retrieved from the database. As shown on the Spring triangle diagram, using simple objects is a core facet to the 'Spring way'. class Article(object): def __init__(self, id=None, title=None, wiki_text=None): self.id = id self.title = title self.wiki_text = wiki_text If we wanted to code this using Python's standard API, our code would be relatively verbose like this: cursor = db.cursor()results = []try: try: cursor.execute("SELECT id, title, wiki_text FROM ARTICLE") temp = cursor.fetchall() for row in temp: results.append( Article(id=temp[0], title=temp[1], wiki_text=temp[2])) except Exception, e: print "execute: Trapped %s" % efinally: try: cursor.close() except Exception, e: print "close: Trapped %s, and throwing away" % ereturn results This isn't that different from the earlier example. The key difference is that instead of assigning fetchall directly to results, we instead iterate over it, generating a list of Article objects. Instead, let's use DatabaseTemplate to cut down on the volume of code return dt.query("SELECT id, title, wiki_text FROM ARTICLE", ArticleMapper()) We aren't done yet. We have to code ArticleMapper, the object class used to iterate over our result set. from springpython.database.core import RowMapperclass ArticleMapper(RowMapper): def map_row(self, row, metadata=None): return Article(id=row[0], title=row[1], wiki_text=row[2]) RowMapper defines a single method: map_row. This method is called for each row of data, and includes not only the information, but also the metadata provided by the database. ArticleMapper can be re-used for every query that performs the same mapping This is slightly different from the parameterized example shown earlier where we defined a row-handling function. Here we define a class that contains the map_row function. But the concept is the same: inject a row-handler to convert the data.
Read more
  • 0
  • 0
  • 3727

article-image-setting-complete-django-e-commerce-store-30-minutes
Packt
21 May 2010
7 min read
Save for later

Setting up a Complete Django E-commerce store in 30 minutes

Packt
21 May 2010
7 min read
In order to demonstrate Django's rapid development potential, we will begin by constructing a simple, but fully-featured, e-commerce store. The goal is to be up and running with a product catalog and products for sale, including a simple payment processing interface, in about half-an-hour. If this seems ambitious, remember that Django offers a lot of built-in shortcuts for the most common web-related development tasks. We will be taking full advantage of these and there will be side discussions of their general use. In addition to building our starter storefront, this article aims to demonstrate some other Django tools and techniques. In this article by Jesse Legg, author of Django 1.2 e-commerce, we will: Create our Django Product model to take advantage of the automatic admin tool Build a flexible but easy to use categorization system, to better organize our catalog of products Utilize Django's generic view framework to expose a quick set of views on our catalog data Finally, create a simple template for selling products through the Google Checkout API (Read more interesting articles on Django 1.2 e-commerce here.) Before we begin, let's take a moment to check our project setup. Our project layout includes two directories: one for files specific to our personal project (settings, URLs, and so on), and the other for our collection of e-commerce Python modules (coleman). This latter location is where the bulk of the code will live. If you have downloaded the source code from the Packt website, the contents of the archive download represents everything in this second location. Designing a product catalog The starting point of our e-commerce application is the product catalog. In the real world, businesses may produce multiple catalogs for mutually exclusive or overlapping subsets of their products. Some examples are: fall and spring catalogs, catalogs based on a genre or sub-category of product such as catalogs for differing kinds of music (for example, rock versus classical), and many other possibilities. In some cases a single catalog may suffice, but allowing for multiple catalogs is a simple enhancement that will add flexibility and robustness to our application. As an example, we will imagine a fictitious food and beverage company, CranStore.com, that specializes in cranberry products: cranberry drinks, food, and desserts. In addition, to promote tourism at their cranberry bog, they sell numerous gift items, including t-shirts, hats, mouse pads, and the like. We will consider this business to illustrate examples as they relate to the online store we are building. We will begin by defining a catalog model called Catalog. The basic model structure will look like this: class Catalog(models.Model): name = models.CharField(max_length=255 slug = models.SlugField(max_length=150) publisher = models.CharField(max_length=300) description = models.TextField() pub_date = models.DateTimeField(default=datetime.now) This is potentially the simplest model we will create. It contains only five, very simple fields. But it is a good starting point for a short discussion about Django model design. Notice that we have not included any relationships to other models here. For example, there is no products ManyToManyField. New Django developers tend to overlook simple design decisions such as the one shown previously, but the ramifications are quite important. The first reason for this design is a purely practical one. Using Django's built-in admin tool can be a pleasure or a burden, depending on the design of your models. If we were to include a products field in the Catalog design, it would be a ManyToManyField represented in the admin as an enormous multiple-select HTML widget. This is practically useless in cases where there could be thousands of possible selections. If, instead, we attach a ForeignKey to Catalog on a Product model (which we will build shortly), we instantly increase the usability of Django's automatic admin tool. Instead of a select-box where we must shift-click to choose multiple products, we have a much simpler HTML drop-down interface with significantly fewer choices. This should ultimately increase the usability of the admin for our users. For example, CranStore.com sells lots of t-shirts during the fall when cranberries are ready to harvest and tourism spikes. They may wish to run a special catalog of touristy products on their website during this time. For the rest of the year, they sell a smaller selection of items online. The developers at CranStore create two catalogs: one is named Fall Collection and the other is called Standard Collection. When creating product information, the marketing team can decide which catalog an individual product belongs to by simply selecting them from the product editing page. This is more intuitive than selecting individual products out of a giant list of all products from the catalog admin page. Secondly, designing the Catalog model this way prevents potential "bloat" from creeping into our models. Imagine that CranStore decides to start printing paper versions of their catalogs and mailing them to a subscriber list. This would be a second potential ManyToManyField on our Catalog model, a field called subscribers. As you can see, this pattern could repeat with each new feature CranStore decides to implement. By keeping models as simple as possible, we prevent all kinds of needless complexity. In addition we also adhere to a basic Django design principle, that of "loose coupling". At the database level, the tables Django generates will be very similar regardless of where our ManyToManyField lives. Usually the only difference will be in the table name. Thus it generally makes more sense to focus on the practical aspects of Django model design. Django's excellent reverse relationship feature also allows a great deal of flexibility when it comes time to using the ORM to access our data. Model design is difficult and planning up-front can pay great dividends later. Ideally, we want to take advantage of the automatic, built-in features that make Django so great. The admin tool is a huge part of this. Anyone who has had to build a CRUD interface by hand so that non-developers can manage content should recognize the power of this feature. In many ways it is Django's "killer app". Creating the product model Finally, let's implement our product model. We will start with a very basic set of fields that represent common and shared properties amongst all the products we're likely to sell. Things like a picture of the item, its name, a short description, and pricing information. class Product(models.Model): name = models.CharField(max_length=300) slug = models.SlugField(max_length=150) description = models.TextField() photo = models.ImageField(upload_to='product_photo', blank=True) manufacturer = models.CharField(max_length=300, blank=True) price_in_dollars = models.DecimalField(max_digits=6, decimal_places=2) Most e-commerce applications will need to capture many additional details about their products. We will add the ability to create arbitrary sets of attributes and add them as details to our products later in this article. For now, let's assume that these six fields are sufficient. A few notes about this model: first, we have used a DecimalField to represent the product's price. Django makes it relatively simple to implement a custom field and such a field may be appropriate here. But for now we'll keep it simple and use a plain and built-in DecimalField to represent currency values. Notice, too, the way we're storing the manufacturer information as a plain CharField. Depending on your application, it may be beneficial to build a Manufacturer model and convert this field to a ForeignKey. Lastly, you may have realized by now that there is no connection to a Catalog model, either by a ForeignKey or ManyToManyField. Earlier we discussed the placement of this field in terms of whether it belonged to the Catalog or in the Product model and decided, for several reasons, that the Product was the better place. We will be adding a ForeignKey to our Product model, but not directly to the Catalog. In order to support categorization of products within a catalog, we will be creating a new model in the next section and using that as the connection point for our products.
Read more
  • 0
  • 0
  • 12509

article-image-user-authentication-codeigniter-17-using-facebook-connect
Packt
21 May 2010
8 min read
Save for later

User Authentication with Codeigniter 1.7 using Facebook Connect

Packt
21 May 2010
8 min read
(Read more interesting articles on CodeIgniter 1.7 Professional Development here.) Registering a Facebook application You need to register a new Facebook Application so that you can get an API key and an Application Secret Key. Head on over to www.facebook.com/developers/ and click on the Set up New Application button in the upper right–hand corner. This process is very similar to setting up a new Twitter application which we covered in the previous article, so I won't bore you with all of the details. Once you've done that, you should have your API key and Application Secret Key. These two things will enable Facebook to recognize your application. Download the Client library When you are on your applications page showing all your applications' information, scroll down the page to see a link to download the Client Library. Once you've downloaded it, simply untar it. There are two folders inside the facebook-platform folder, footprints and php. We are only going to be using the php folder. Open up the php folder; there are two files here that we don't need, facebook_desktop.php and facebook_mobile.php—you can delete them. Finally, we can copy this folder into our application. Place it in the system/application/libraries folder, and then rename the folder to facebook. This helps us to keep our code tidy and properly sorted. Our CodeIgniter Wrapper Before we start coding, we need to know what we need to code in order to make the Facebook Client Library work with our CodeIgniter installation. Our Wrapper library needs to instantiate the Facebook class with our API Key and Secret Application Key. We'll also want it to create a session for the user when they are logged in. If a session is found but the user is not authenticated, we will need to destroy the session. You should create a new file in the system/application/libraries/ folder, called Facebook_connect.php. This is where the Library code given next should be placed. Base class The Base Class for our Facebook Connect Wrapper Library is very simple: <?phprequire_once(APPPATH . 'libraries/facebook/facebook.php');class Facebook_connect{ var $CI; var $connection; var $api_key; var $secret_key; var $user; var $user_id; var $client;}?> The first thing that our Library needs to do is to load the Facebook library—the one we downloaded from facebook.com. We build the path for this by using APPPATH, a constant defined by CodeIgniter to be the path of the application folder. Then, in our Class we have a set of variables. The $CI variable is the variable in which we will store the CodeIgniter super object; this allows us to load CodeIgniter resources (libraries, models, views, and so on) in our library. We'll only be using this to load and use the CodeIgniter Session library, however. The $connection variable will contain the instance of the Facebook class. This will allow us to grab any necessary user data and perform any operations that we like, such as updating a user's status or sending a message to one of their friends. The next few variables are pretty self-explanatory—they will hold our API Key and Secret Key. The $user variable will be used to store all of the information about our user, including general details about the user such as their profile URL and their name. The $user_id variable will be used to store the user ID of our user. Finally, the $client variable is used to store general information about our connection to Facebook, including the username of the user currently using the connection, amongst other things such as server addresses to query for things like photos. Class constructor Our class constructor has to do a few things in order to allow us to authenticate our users using Facebook Connect. Here's the code: function Facebook_connect($data){ $this->CI =& get_instance(); $this->CI->load->library('session'); $this->api_key = $data['api_key']; $this->secret_key = $data['secret_key']; $this->connection = new Facebook($this->api_key, $this->secret_key); $this->client = $this->connection->api_client; $this->user_id = $this->connection->get_loggedin_user(); $this->_session();} The first line in our function should be new to everyone reading this article. The function get_instance() allows us to assign the CodeIgniter super object by reference to a local variable. This allows us to use all of CodeIgniter's syntax for loading libraries, and so on; but instead of using $this->load we would use $this->CI->load. But of course it doesn't just allow us to use the Loader—it allows us to use any CodeIgniter resource, as we normally would inside a Controller or a Model. The next line of code gives us a brilliant example of this: we're loading the session library using the variable $this->CI rather than the usual $this. The next two lines simply set the values of the API key and Secret Application Key into a class variable so that we can reference it throughout the whole class. The $data array is passed into the constructor when we load the library in our Controller. More on that when we get there. Next up, we create a new instance of the Facebook Class (this is contained within the Facebook library that we include before our own class code) and we pass the API Key and Secret Application Key through to the class instance. This is all assigned to the class variable $this->connection, so that we can easily refer to it anywhere in the class. The next two lines are specific parts of the overall Facebook instance. All of the client details and the data that helps us when using the connection are stored in a class variable, in order to make it more accessible. We store the client details in the variable $this->client. The next line of code stores all of the details about the user that were provided to us by the Facebook class. We store this in a class variable for the same reason as storing the client data: it makes it easier to get to. We store this data in $this->user_id. The next line of code calls upon a function inside our class. The underscore at the beginning tells CodeIgniter that we only want to be able to use this function inside this class; so you couldn't use it in a Controller, for example. I'll go over this function shortly. _session(); This function manages the user's CodeIgniter session. Take a look at the following code: function _session(){ $user = $this->CI->session->userdata('facebook_user'); if($user === FALSE && $this->user_id !== NULL) { $profile_data = array('uid','first_name', 'last_name', 'name', 'locale', 'pic_square', 'profile_url'); $info = $this->connection->api_client-> users_getInfo($this->user_id, $profile_data); $user = $info[0]; $this->CI->session->set_userdata('facebook_user', $user); } elseif($user !== FALSE && $this->user_id === NULL) { $this->CI->session->sess_destroy(); } if($user !== FALSE) { $this->user = $user; }} This function initially creates a variable and sets its value to that of the session data from the CodeIgniter session library. Then we go through a check to see if the session is empty and the $this->user_id variable is false. This means that the user has not yet logged in using Facebook Connect. So we create an array of the data that we want to get back from the Facebook class, and then use the function users_getInfo() provided by the class to get the information in the array that we created. Then we store this data into the $user variable and create a new session for the user. The next check that we do is that if the $user variable is not empty, but the $this->user_id variable is empty, then the user is not authenticated on Facebook's side so we should destroy the session. We do this by using a function built in to the Session Library sess_destroy(); Finally, we check to see if the $user variable is not equal to FALSE. If it passes this check, we set the $this->user class variable to that of the local $user variable.
Read more
  • 0
  • 0
  • 1839
article-image-user-authentication-codeigniter-17-using-twitter-oauth
Packt
21 May 2010
6 min read
Save for later

User Authentication with Codeigniter 1.7 using Twitter oAuth

Packt
21 May 2010
6 min read
(Read more interesting articles on CodeIgniter 1.7 Professional Development here.) How oAuth works Getting used to how Twitter oAuth works takes a little time. When a user comes to your login page, you send a GET request to Twitter for a set of request codes. These request codes are used to verify the user on the Twitter website. The user then goes through to Twitter to either allow or deny your application access to their account. If they allow the application access, they will be taken back to your application. The URL they get sent to will have an oAuth token appended to the end. This is used in the next step. Back at your application, you then send another GET request for some access codes from Twitter. These access codes are used to verify that the user has come directly from Twitter, and has not tried to spoof an oAuth token in their web browser. Registering a Twitter application Before we write any code, we need to register an application with Twitter. This will give us the two access codes that we need. The first is a consumer key, and the second is a secret key. Both are used to identify our application, so if someone posts a message to Twitter through our application, our application name will show up alongside the user's tweet. To register a new application with Twitter, you need to go to http://www.twitter.com/apps/new. You'll be asked for a photo for your application and other information, such as website URL, callback URL, and a description, among other things. You must select the checkbox that reads Yes, use Twitter for login or you will not be able to authenticate any accounts with your application keys. Once you've filled out the form, you'll be able to see your consumer key and consumer secret code. You'll need these later. Don't worry though; you'll be able to get to these at any time so there's no need to save them to your hard drive. Here's a screenshot of my application: Downloading the oAuth library Before we get to write any of our CodeIgniter wrapper library, we need to download the oAuth PHP library. This allows us to use the oAuth protocol without writing the code from scratch ourselves. You can find the PHP Library on the oAuth website at www.oauth.net/code. Scroll down to PHP and click on the link to download the basic PHP Library; or just visit: http://oauth.googlecode.com/svn/code/php/—the file you need is named OAuth.php. Download this file and save it in the folder system/application/libraries/twitter/—you'll need to create the twitter folder. We're simply going to create a folder for each different protocol so that we can easily distinguish between them. Once you've done that, we'll create our Library file. Create a new file in the system/application/libraries/ folder, called Twitter_oauth.php. This is the file that will contain functions to obtain both request and access tokens from Twitter, and verify the user credentials. The next section of the article will go through the process of creating this library alongside the Controller implementation; this is because the whole process requires work on both the front-end and the back-end. Bear with me, as it could get a little confusing, especially when trying to implement a brand new type of system such as Twitter oAuth. Library base class Let's break things down into small sections. The following code is a version of the base class with all its guts pulled out. It simply loads the oAuth library and sets up a set of variables for us to store certain information in. Below this, I'll go over what each of the variables are there for. <?phprequire_once(APPPATH . 'libraries/twitter/OAuth.php');class Twitter_oauth{ var $consumer; var $token; var $method; var $http_status; var $last_api_call;}?> The first variable you'll see is $consumer—it is used to store the credentials for our application keys and the user tokens as and when we get them. The second variable you see on the list is $token—this is used to store the user credentials. A new instance of the oAuth class OAuthConsumer is created and stored in this variable. Thirdly, you'll see the variable $method—this is used to store the oAuth Signature Method (the way we sign our oAuth calls). Finally, the last two variables, $http_status and $last_api_call, are used to store the last HTTP Status Code and the URL of the last API call, respectively. These two variables are used solely for debugging purposes. Controller base class The Controller is the main area where we'll be working, so it is crucial that we design the best way to use it so that we don't have to repeat our code. Therefore, we're going to have our consumer key and consumer secret key in the Controller. Take a look at the Base of our class to get a better idea of what I mean. <?phpsession_start();class Twitter extends Controller{ var $data; function Twitter() { parent::Controller(); $this->data['consumer_key'] = ""; $this->data['consumer_secret'] = "";} The global variable $data will be used to store our consumer key and consumer secret. These must not be left empty and will be provided to you by Twitter when creating your application. We use these when instantiating the Library class, which is why we need it available throughout the Controller instead of just in one function. We also allow for sessions to be used in the Controller, as we want to temporarily store some of the data that we get from Twitter in a session. We could use the CodeIgniter Session Library, but it doesn't offer us as much flexibility as native PHP sessions; this is because with native sessions we don't need to rely on cookies and a database, so we'll stick with the native sessions for this Controller.
Read more
  • 0
  • 0
  • 2772

article-image-creating-custom-content-type-paster-plone-3
Packt
20 May 2010
18 min read
Save for later

Creating a Custom Content Type with Paster in Plone 3

Packt
20 May 2010
18 min read
(Further resources on Plone see here.) we have used a graphic application (ArgoUML) to draw a UML model that was automatically transformed by ArchGenXML into an Archetypes-based content type for Plone. In this article, we'll create a content type product with another tool, paster. It's not a graphic application, but it's as easy to use as writing a few characters. We used paster earlier to create a buildout-based Zope instance and an egg-structured Plone product. Here we'll use it to create a full Archetype product, its schema fields, and even the required tests to make sure everything is working as intended Creating an Archetypes product with paster There are several steps to take with paster to produce a full and useful content type. The first one should be the creation of the structure, meaning the product directory organization. Getting ready The final destination of this product, at least at development stage, is the src folder of our buildout directory. There is where we place our packages source code while we are working on them, until they become eggs (to see how to turn them into eggs read Submitting products to an egg repository). Thus go to your buildout directory and then get inside the src folder: cd ./src Make sure you have the latest ZopeSkel installed. ZopeSkel is the name of a Python package with a collection of skeletons and templates to create commonly used Zope and Plone projects via a paster command. easy_install -U ZopeSkel   How to do it… Create a package for the new add-on product: We are going to create a new package called pox.video. The pox prefix is taken from PloneOpenX (the website we are working on) and will be the namespace of our product. paster create -t archetype Fix the main configure.zcml file to prevent errors: Open the just created configure.zcml file in the pox/video folder and comment the internationalization registration like this: <!-- <i18n:registerTranslations directory="locales" /> --> Update the Zope instance with the new product: To let Zope know that there's new code to be used, let's update our instance buildout.cfg file. In the main [buildout] section, modify the eggs and develop parameters like this: [buildout] ... eggs = ... pox.video ... develop = src/pox.video Automatically add the product in a Plone site: We can install our brand new product automatically during buildout. So add a pox.video line inside the [plonesite] part's products parameter: [plonesite] recipe = collective.recipe.plonesite ... products = ... pox.video Rebuild and relaunch the Zope instance: Build your instance and, if you want to, launch it to check that the pox.video product is installed (not strictly necessary though). ./bin/buildout ./bin/instance fg How it works… So far we have a skeleton product, which is composed basically of boilerplate (we will build on it further). However, it has all the necessary code to be installed, which is important. The paster command of Step 1 in How to do it… creates a package using the archetype available template. When run, it will output some informative text and then a short wizard will be started to select some options. The most important are the first five ones: Option Value Enter project name pox.video Expert mode? Choose whatever option you like. Project Title Video Version 1.0 Description Video content type for PloneOpenX website Add whatever you want to the remaining options (if you chose other than easy mode), or just hit Enter to each one. After selecting the last option, you'll get an output like this (a little longer actually): Creating template basic_namespace Creating directory .pox.video Creating template archetype Recursing into +namespace_package+ Recursing into +package+ Recursing into content Recursing into interfaces Recursing into portlets Recursing into profiles Recursing into tests ... The project you just created has local commands. These can be used from within the product. usage: paster COMMAND Commands: addcontent Adds plone content types to your project For more information: paster help COMMAND The first group of lines tells us something about the created directory structure. We have a pox.video (project name) folder, containing a pox (namespace) folder, which contains a video (package) folder, which in turn contains several sub-packages: content, interfaces, portlets, profiles, and tests. In the following sections, we are going to deal with all of them except portlets, which will be tackled in Creating a portlet package, Customizing a new portlet according to our requirements, and Testing portlets. The second group of lines (after the ellipsis) gives us very important information: we can use particular local commands inside our fresh product. More of this in the next section. Step 2 in the preceding procedure is to tell Zope about the new available package. By adding pox.video in the eggs parameter, we add it in Zope's PYTHONPATH. We also have to add the package's location in the develop parameter. If not, the buildout process would try to fetch it from some of the URLs listed in the find-links parameter. During start up, Zope 2 loads (Five does the job actually) configuration files, usually configure.zcml, for all the products and packages inside the folders that are listed in the [instance] section's products parameter. For other Python packages outside those folders, a ZCML slug is required for the product to be loaded. Fortunately, from Plone 3.3 onwards, the ZCML slug is not needed if packages to be installed use z3c.autoinclude, which automatically detects and includes ZCML files. Although we were not aware of that, when we created the pox.video package with paster, z3c.autoinclude was added as an entry point in the setup.py file. Open it in the main pox.video folder to check it: ... setup(name='pox.video', version=version, description="Video content type for PloneOpenX website", ... entry_points=""" # -*- entry_points -*- [z3c.autoinclude.plugin] target = plone """, ... ) For those packages that don't have this feature, we must explicitly insert a reference to the package in the zcml parameter of the [instance] section like we did in Taking advantage of an enhanced interactive Python debugger with ipdb: [instance] ... # If you want to register ZCML slugs for any packages, # list them here. # e.g. zcml = my.package my.other.package zcml = iw.debug There's more… Do not forget to test your changes (paster changes in fact)! Fortunately, paster creates automatically a tests sub-package and a package-level README.txt file with the first part of a test (logging into our website). Feel free to take a look at it, as it is a very good example of doctest. Nevertheless, it really doesn't test too much for the time being. It will be more productive after adding some features to the product. You may find it really useful to read the content types section from the online Plone Developer Manual at http://plone.org/documentation/manual/developer-manual/archetypes. See Also Submitting products to an egg repository Taking advantage of an enhanced interactive Python debugger with ipdb Adding a content type into a product Adding fields to a content type Adding a custom validator to a content type Creating a portlet egg with paster Customizing a new portlet according to our requirements Testing portlets Adding a content type into a product In Creating an Archetypes product with paster, we were able to create a package shell with all the necessary code to install a product, although it was unproductive. We are now going to add some useful functionality by means of, again, our dear paster. Getting ready When we ran paster in Creating an Archetypes product with paster, we highlighted some of its output, copied below: The project you just created has local commands. These can be used from within the product. Paster local commands are available inside the project folder. So let's move inside it: cd ./src/pox.video How to do it… To add a new content type inside the product, run the following command: paster addcontent contenttype How it works… This will run the addcontent paster command with its contenttype template. After a short wizard asking for some options, it will produce all the code we need. Option Value Enter Video Enter contenttype_description FLV video file Enter folderish False Enter global_allow True Enter allow_discussion True/False, whatever - You'll get an output like this: ... Inserting from README.txt_insert into /pox.video/pox/video/README.txt Recursing into content Recursing into interfaces Recursing into profiles Recursing into default Recursing into types If you need more than just one content type in your product, you can run the paster addcontent contenttype command as many times as you want. There's no need to modify, buildout.cfg file, as we have already made all the required changes. If you didn't make these modifications, please refer to Creating an Archetypes product with paster. Open the interface file in ./src/pox.video/pox/video/interface/video.py: from zope import schema from zope.interface import Interface from pox.video import videoMessageFactory as _ class IVideo(Interface): """Description of the Example Type""" # -*- schema definition goes here -*- Empty interfaces, like this one, are called marker interfaces. Although they provide some information (they can be used to associate a class with some functionality as we will see in Using the ZCA to extend a third party product: Collage), they lack attributes and methods information (that is, their promised functionalities), and consequently and worse, they don't document. Interfaces don't exist in Python. However, Zope 3 has incorporated this concept to let components interact easier. All attributes and methods declarations in interfaces are a contract (not a binding one, though) with the external world. For more information about zope.interface, visit http://wiki.zope.org/Interfaces/FrontPage. The new content type class is in the video.py file located in the ./src/pox.vieo/pox/video/content package. Let's go through it and explain its pieces. """Definition of the Video content type """ from zope.interface import implements, directlyProvides from Products.Archetypes import atapi from Products.ATContentTypes.content import base from Products.ATContentTypes.content import schemata from pox.video import videoMessageFactory as _ from pox.video.interfaces import IVideo from pox.video.config import PROJECTNAME All paster-generated content types inherit from basic ATContentTypes, which is good given the large number of products available for them. Check the Products.ATContentTypes package for plenty of good working examples. VideoSchema = schemata.ATContentTypeSchema.copy() + atapi.Schema(( # -*- Your Archetypes field definitions here ... -*- )) Schemas specify the fields available in content types. In our case, the Video content type is a plain copy of ATContentTypeSchema, which already includes all fields necessary to support Dublin Core convention. Dublin Core is supported thanks to the BaseObject and ExtensibleMetadata modules in the Products.Archetypes package. VideoSchema here is the result of the addition (yes, we can actually add schemas) of two other schemas: the aforementioned ATContentTypeSchema and the new empty one created with the atapi.Schema(()) method, which expects a tuple argument (check the double brackets). Up to ZopeSkel 2.16 (paster's package) the storage of title and description fields are changed to AnnotationStorage. This reduces performance and therefore it would be better to change it by removing these lines letting Archetypes deal with regular AttributeStorage: # Set storage on fields copied from ATContentTypeSchema, # making sure # they work well with the python bridge properties. VideoSchema['title'].storage = atapi. AnnotationStorage() VideoSchema['description'].storage = atapi. AnnotationStorage() here are plans to remove this from ZopeSkel, but there's no release date yet for it. After schema definition, we call finalizeATCTSchema to re-order and move some fields inside our schema according to Plone standard. It's advisable to get familiar with its code in the Products.ATContentTypes.content.schema module: schemata.finalizeATCTSchema(VideoSchema, moveDiscussion=False) Once defined its schema the real class is created. As we said earlier, it inherits from base.ATCTContent; this will be changed for our Video content type. class Video(base.ATCTContent): """FLV video file""" implements(IVideo) meta_type = "Video" schema = VideoSchema title = atapi.ATFieldProperty('title') description = atapi.ATFieldProperty('description') # -*- Your ATSchema to Python Property Bridges Here ... -*- atapi.registerType(Video, PROJECTNAME) The first line in our class body specifies that it implements IVideo interface (interfaces/video.py file). then VideoSchema is associated with the class. ATFieldProperty is required to create ATSchema to Python Property bridges. These are recommended for fields of a schema using AnnotationStorage. If you still have title and description fields storage as AnnotationStorage, you should keep these lines. Otherwise you can safely remove them. And finally, the atapi.registerType() call adds all getters and setters to the Video class. This is Archetypes' magic. You define just a schema and Archetypes will automatically create all methods needed to interact with the class. There's more… We do have some more interesting code now, that's why we should be more careful with it and test it. Again, paster has appended several functional tests in the README.txt file, including the creation (as Manager and Contributor users), modification, and deletion of a Video object. Test the product with the following command: ./bin/instance test -s pox.video We'd like to highlight the block of statements regarding the creation of content as a contributor member: Let's logout and then login as 'contributor', a portal member that has the contributor role assigned. >>> browser.getLink('Log out').click() >>> browser.open(portal_url) >>> browser.getControl(name='__ac_name').value = 'contributor' >>> browser.getControl(name='__ac_password').value = default_password >>> browser.getControl(name='submit').click() This contributor member isn't mentioned anywhere inside the test. Nevertheless the login action doesn't fail. How can that be possible if there's no contributor member included by default in the PloneTestCase base class, like default_user or portal_owner? If we check the base.py file inside the tests sub-package of our product, we'll see that the FunctionalTestCase class has a special afterSetUp method, which is called just before the real test begins and registers the contributor member above. Could we have created the user inside the test? Definitely, because test code is a set of Python statements and we can do whatever we want with them. Is it sensible to perform this kind of set up actions inside the test code? Absolutely not. functional tests should be conceived as black-box tests, from the sheer end-user point of view. This means that code inside a functional test shouldn't assume anything about the underlying environment, but behave as if a regular user were acting through the user interface. Anything we need during testing that shouldn’t be done by the user must be placed outside the test code, as in this example. See also Creating an Archetypes product with paster Working with paster generated test suites Zope Functional testing Using the ZCA to extend a third party product: Collage Changing the base class in paster content types All paster-created (non-folderish) content types inherit from the basic ATCTContent class, which comes with ATContentTypeSchema. However, this is a very basic content type: title, description, and some more metadata fields. On top of this, we intend to upload videos to our website, not just text. ATContentTypes are native to Plone and many community developers had released extensions or plugins for them, such as LinguaPlone. That's why it is prudent to stay close to them. We are now going to change the ATCTContent parent class for ATFile to automatically inherit all the benefits, including the file upload field. How to do it… Open the video.py file inside the content sub-package of your product and make these changes. Be aware of commented lines — they can be just removed, but we wanted to keep them here to remark what's going on. Import the base class and interface to be used: from Products.Archetypes import atapi # from Products.ATContentTypes.content import base from Products.ATContentTypes.content import file from Products.ATContentTypes.interface.file import IATFile from Products.ATContentTypes.content import schemata This way we are importing interface and class of the out-of-the-box File content type. Change original schema: # VideoSchema = schemata.ATContentTypeSchema.copy() + # atapi.Schema(( VideoSchema = file.ATFileSchema.copy() + atapi.Schema(( # -*- Your Archetypes field definitions here ... -*- )) Now, our VideoSchema includes File fields. Change the base class and implemented interface: # class Video(base.ATCTContent): class Video(file.ATFile): """ pox Video """ # implements(IVideo) implements(IATFile,IVideo The last step is to change the parent class of Video so that now it inherits from ATFile instead of just ATCTContent. And then we adjust the interfaces this class now implements. Change the view action URL: Open profiles/default/types/Video.xml file and amend the url_expr attribute in View action by adding /view. <?xml version="1.0"?> <object name="Video" meta_type="Factory-based Type Information with dynamic views" i18n_domain="pox.video" action_id="view" category= "object" condition_expr="" url_expr="string:${object_url}/view" visible="True"> <permission value="View" /> </action> ... </object> Tell Plone to use the new action URL in listings: Add a propertiestool.xml file inside the profiles/default folder with this code: <?xml version="1.0"?> <object name="portal_properties" meta_type= "Plone Properties Tool"> <object name="site_properties" meta_type="Plone Property Sheet"> <property name="typesUseViewActionInListings" type= "lines" purge="False"> <element value="Video"/> </property> </object> </object> Relaunch your instance and reinstall the product. By restarting the Zope instance all of the latest changes will be applied: ./bin/instance fg Go to http://localhost:8080/plone/prefs_install_products_form and reinstall the product. Create a new Video object:Inside your Plone site, click on the Add new... drop-down menu and select the Video option. It should look like this. How it works… Since the first creation of the almost empty product (full of boilerplate, though), in Creating an Archetypes product with paster, we haven't tried to use it, except for the tests we have run. We can now say that it has grown up and it's ready to be seen in action. In Steps 1 to 3 above, we changed some of the basics in paster's original class and its schema to inherit all the benefits of another existing content type: ATFile. If you had tried to create a Video content type before Step 4, after saving, you would have been automatically prompted to download the file you just uploaded. Why's that? The reason is we inherited our class from ATFile, which has a special behavior (like ATImage) regarding its URLs. Files and images uploaded to a Plone site (using regular content types) are downloadable via their natural URL. For example, if you browse to http://yoursite.com/document.pdf, you will be asked to download the file. Alternatively, if you want to open the web page with a download link and metadata, you should use http://yoursite.com/document.pdf/view. That's why we had to change the view URL for our content type in Video.xml (Step 4) for users to be able to open an inline video player (as we plan to). All files included in the profiles folder are used by GenericSetup during installation of the product and are to give some information that Python code doesn't provide, such as whether we'll let users post comments inside the content types (allow_discussion). Plone object listings (including search results) tend to create links to contents without the /view suffix. We must explicitly tell Plone that when listing videos, the suffix should be appended to prevent a download attempt. Fortunately, Plone has foreseen this could have happened. Thus there's no need to modify or override every single list. If the content type name is listed in the special typesUseViewActionInListings property, it will work as expected. Plone object listings (including search results) tend to create links to contents without the /view suffix. We must explicitly tell Plone that when listing videos, the suffix should be appended to prevent a download attempt. Fortunately, Plone has foreseen this could have happened. Thus there's no need to modify or override every single list. If the content type name is listed in the special typesUseViewActionInListings property, it will work as expected. Changes in Step 5 will make the site_properties update its typesUseViewActionInListings property. By including purge="False" in <property /> tag, we prevent other existing values (typically File and Image) in the property from being removed.
Read more
  • 0
  • 0
  • 1515

article-image-building-image-slideshow-using-scripty2
Packt
20 May 2010
10 min read
Save for later

Building an Image Slideshow using Scripty2

Packt
20 May 2010
10 min read
In our previous Scripty2 article, we saw the basics of the Scripty2 library, we saw the UI elements available, the fx transitions and some effects. We even build an small example of a image slide effect. This article is going to be a little more complex, just a little, so we are able to build a fully working image slideshow. If you haven't read our previous article, it would be interesting and useful if you do so before continuing with this one. You can find the article here: Scripty2 in Action Well, now we can continue. But first, why don't we take a look at what we are going to build in this article: As we can see in the image we have three main elements. The biggest one will be where the main images are placed, there is also one element where we will make the slide animation to take place. There's also a caption and some descriptive text for the image and, to the right, we have the miniatures slider, clicking on them will make the main image to also slide out and the new one to appear. Seems difficult to achieve? Don't worry, we will make it step by step, so it's very easy to follow. Our main steps are going to be these: First we we will create the html markup and css necessary, so our page looks like the design. Next step will be to create the slide effect for the available images to the right. And our final step will be to make the thumbnail slider to work. Good, enough talking, let's start with the action. Creating the necessary html markup and css We will start by creating an index.html file, with some basic html in it, just like this: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xml_lang="es-ES" lang="es-ES" ><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>Scripty2</title><link rel="stylesheet" href="css/reset.css" type="text/css" /><link rel="stylesheet" href="css/styles.css" type="text/css" /> </head><body id="article"> <div id="gallery"> </div> <script type="text/javascript" src="js/prototype.s2.min.js"></script> </body></html> Let's take a look at what we have here, first we are including a reset.css file, this time, for a change, we are going to use the Yahoo one, which we can find in this link: http://developer.yahoo.com/yui/3/cssreset/ We will create a folder called css, and a reset.css file inside it, where we will place the yahoo code. Note that we could also link the reset directly from the yahoo site: <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.1.1/build/cssreset/reset-min.css"> Just below the link to the reset.css file, we find a styles.css file. This file will be the place where we are going to place our own styles. Next we find a div: <div id="gallery"> </div> This will be our placeholder for the entire slideshow gallery. Then one last thing, the link to the Scripty2 library: <script type="text/javascript" src="js/prototype.s2.min.js"></script> Next step will be to add some styles in our styles.css file: html, body{ background-color: #D7D7D7; }#gallery{ font-family: arial; font-size: 12px; width: 470px; height: 265px; background-color: #2D2D2D; border: 1px solid #4F4F4F; margin: 50px auto; position: relative;} Mostly, we are defining a background colour for the page, and then some styles for our gallery div like its width, height, margin and also a background colour. With all this our page will look like the following screenshot: We will need to keep working on this, first in our index.html file, we need a bit more of code: <div id="gallery"> <div id="photos_container"> <img src="./img/image_1.jpg" title="Lorem ipsum" /> <img src="./img/image_1.jpg" title="Lorem ipsum" /> <img src="./img/image_1.jpg" title="Lorem ipsum" /> <img src="./img/image_1.jpg" title="Lorem ipsum" /> </div> <div id="text_container"> <p><strong>Lorem Ipsum</strong><br/>More lorem ipsum but smaller text</p> </div> <div id="thumbnail_container"> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum"/> </div></div> We have placed three more divs inside our main gallery one. One of them would be the photos-photos_container, where we place our big photos. The other two will be one for the text- text_container, and the other for the thumbnail images, that will be thumbnail_container. After we have finished with our html, we need to work with our css. Remember we are going to do it in our styles.css: #photos_container{ width: 452px; height: 247px; background-color: #fff; border: 1px solid #fff; margin-top: 8px; margin-left: 8px; overflow: hidden;}#text_container{ width: 377px; height: 55px; background-color: #000000; color: #ffffff; position: absolute; z-index: 2; bottom: 9px; left: 9px;}#text_container p{ padding: 5px; }#thumbnail_container{ width: 75px; height: 247px; background-color: #000000; position: absolute; z-index: 3; top: 9px; right: 9px;}#thumbnail_container img{ margin: 13px 13px 0px 13px; }strong{ font-weight: bold; } Here we have added styles for each one of our divs, just quite basic styling for the necessary elements, so our page now looks a bit more like the design: Though this looks a bit better than before, it still does nothing and that's going to be our next step. Creating the slide effect First we need some modifications to our html code, this time, though we could use id tags in order to identify elements, we are going to use rel tags. So we can see a different way of doing things. Let's then modify the html: <div id="photos_container"> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="1"/> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="2"/> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="3"/> <img src="./img/image_1.jpg" title="Lorem ipsum" rel="4"/> </div> <div id="text_container"> <p><strong>Lorem Ipsum</strong><br/>More lorem ipsum but smaller text</p> </div> <div id="thumbnail_container"> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="1"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="2"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="3"/> <img src="./img/thumbnail_1.jpg" title="Lorem ipsum" rel="4"/> </div> Note the difference, we have added rel tags to each one of the images in every one of the divs. Now we are going to add a script after the next line: <script type="text/javascript" src="js/prototype.s2.min.js"></script> The script is going to look like this: <script type="text/javascript"> $$('#thumbnail_container img').each(function(image){ image.observe('click', function(){ $$('#photos_container img[rel="'+this. readAttribute('rel')+'"]').each(function(big_image){ alert(big_image.readAttribute('title')); }) }); });</script> First we select all the images inside the #thumbnail_container div: $$('#thumbnail_container img') Then we use the each function to loop through the results of this selection, and add the click event to them: image.observe('click', function(){ This event will fire a function, that will in turn select the bigger images, the one in which the rel attribute is equal to the rel attribute of the thumbnail: $$('#photos_container img[rel="'+this.readAttribute('rel')+'"]').each(function(big_image){ We know this will return only one value, but as the selected could, theoretically, return more than one value, we need to use the each function again. Note that we use the this.readAttribute('rel') function to read the value of the rel attribute of the thumbnail image. Then we use the alert function to show the title value of the big image: alert(big_image.readAttribute('title')); If we now click on any of the thumbnails, we will get an alert, just like this: We have done this just to check if our code is working and we are able to select the image we want. Now we are going to change this alert for something more interesting. But first, we need to do some modifications to our styles.css file, we will modify our photos container styles: #photos_container{ width: 452px; height: 247px; background-color: #fff; border: 1px solid #fff; margin-top: 8px; margin-left: 8px; overflow: hidden; position: relative;} Only to add the position relate in it, this way we will be able to absolute position the images inside it, adding these styles: #photos_container img{ position: absolute;} With these changes we are done with the styles for now, return to the index.html file, we are going to introduce some modifications here too: <script type="text/javascript" src="js/prototype.s2.min.js"></script> <script type="text/javascript"> var current_image = 1; $$('#photos_container img').each(function(image){ var pos_y = (image.readAttribute('rel') * 247) - 247; image.setStyle({top: pos_y+'px'}); })... I've placed the modifications in bold, so we can concentrate on them. What have we here? We are creating a new variable, current_image, so we can save which is the current active image. At page load this will be the first one, so we are placing 1 to its value. Next we loop through all of the big images, reading its rel attribute, to know which one of the images are we working with. We are multiplying this rel attribute with 247, which is the height of our div. We are also subtracting 247 so the first image is at 0 position. note Just after this, we are using prototype's setStyle function to give each image its proper top value. Now, I'm going to comment one of the css styles: #photos_container{ width: 452px; height: 247px; background-color: #fff; border: 1px solid #fff; margin-top: 8px; margin-left: 8px; //overflow: hidden; position: relative;} You don't need to do this, I' will do it for you, so we can see the result of our previous coding, and then I will turn back and leave it as it was before, prior to continuing. So our page would look like the next image: As we see in the image, all images are one on top of the others, this way we will be able to move them in the y axis. We are going to achieve that by modifying this code: $$('#thumbnail_container img').each(function(image){ image.observe('click', function(){ $$('#photos_container img[rel="'+this. readAttribute('rel')+'"]').each(function(big_image){ alert(big_image.readAttribute('title')); }) }); });
Read more
  • 0
  • 0
  • 10976
article-image-using-flowplayer-plone-3
Packt
19 May 2010
5 min read
Save for later

Using Flowplayer in Plone 3

Packt
19 May 2010
5 min read
This article is the third and the final section of this article series. The following articles are the initial parts of the series. Managing Audio Content in Plone 3.3 Audio Enhancements with p4a.ploneaudio in Plone 3.3 (For more resources on Plone, see here.) Including audio into HTML Generally, we have two options to include a sound file on a HTML page: Streaming Non streaming Another option is to simply include a link to the file like this: <a href="example.mp3" type="audio/x-mpeg" title="MP3 audiofile , ... kB">example.mp3 </a> This is the standard way Plone includes files into the visual editor. The advantage of this approach is that virtually everyone is able to access the file in some way. What happens with the file after it has been downloaded depends on the client browser and how it is configured. The shortcoming of this method is that we depend on an external player to listen to the audio. Probably one needs to download the file and start the player manually. Including audio with plugin elements Another option to spread an audio file is to use the embed element or the object element. The former looks like this: <embed src="example.mp3"> The embed element was introduced by Netscape in browser version 2.0. However, it has not yet made it into the HTML standard, and probably will never do so. An alternative element to the Netscape variant is the object element that was introduced by Microsoft. Including an example.mp3 file located in the data folder looks like this: <object type="audio/x-mpeg" data="data/example.mp3" width="200" height="20"> <param name="src" value="data/example.mp3"> <param name="autoplay" value="false"> <param name="autoStart" value="0"> alt : <a href="data/example.mp3">example.mp3</a> </object> Including audio with the embed or the object element assumes that there is a plugin installed on the client side that can play the multimedia format. In most cases, we can't tell what the client is equipped with and want a more robust solution. The third way to include audio into your site is Flash. We still need a plugin on the client side, but Flash is more widespread than audio player plugins. There are a couple of free audio players written in Flash. An older but easy-to-use Flash player is EMFF. A custom view with an embedded audio player What we do now is to write a custom view for the audio-enhanced File content type of Plone. We reuse the mm.enhance product we created in the previous article and add the additional code there. We utilize the p4a.audio.interfaces.IAudioEnhanced interface to register our view on. Let's do so: <browser:page for="p4a.audio.interfaces.IAudioEnhanced" name="my-audioplayer-view" class=".browser.AudioPlayerView" permission="zope2.View" template="player.pt" /> <browser:resourceDirectory directory="thirdparty/emff" name="emff" /> The page is named my-audioplayer-view and has the AudioPlayerView view class in the browser module. Further, we register a thirdparty/emff directory where we can put the Flash resources of the Flash player. Next, we need to create this view class and add the player.pt template. We fill the template with the HTML code we get from the EMFF code generator: Using the EMFF code generator Choose the first option URL to MP3, though it doesn't really matter what you write into the text field. The value is overridden with the name we retrieve from our context object. For the HTML version, you can either choose HTML or XHTML as Plone 3 doesn't output valid XHTML itself. Nevertheless, XHTML might still be the better option, as it is future proof. Selecting XHTML closes the param elements inside of the object element. We can copy this literally into our Zope page template. <object type="application/x-shockwave-flash" data="emff_lila_info.swf" width="200" height="55"> <param name="movie" value="emff_lila_info.swf" /> <param name="bgcolor" value="#00ff00" /> <param name="FlashVars" value="src=example.mp3&amp;autostart=yes" /> </object> The Plone template is a standard one using the main_template. We copy the generated code from the bottom of the codegenerator window and put into the main slot of the template. There are just two changes we make. One is the location of the Flash file, which is registered as a resource, and the other is the audio file itself, which is our context. <html xml_lang="en" lang="en" i18n:domain="p4a.audio" metal:use-macro="context/main_template/macros/master"> <body> <div metal:fill-slot="main"> <object type="application/x-shockwave-flash" data=" ++resource++emff/emff_lila_info.swf" width="200" height="55"> <param name="movie" value="emff_lila_info.swf" /> <param name="bgcolor" value="#ffffff" /> <param name="FlashVars" value="src=example.mp3&amp;autostart=yes" tal:attributes="value string_src=${context/getId}&amp; autostart=yes" /> </object> </div> </body> </html> Next, we download the necessary Flash code from its website. The player is provided as a ZIP package with all sources and stuff included. We need to copy the chosen skin file to the thirdparty/emff directory of our mm.enhance product. In our example we used the emff_lila_info skin.
Read more
  • 0
  • 0
  • 1254

article-image-django-12-e-commerce-data-integration
Packt
19 May 2010
7 min read
Save for later

Django 1.2 E-commerce: Data Integration

Packt
19 May 2010
7 min read
(Read more interesting articles on Django 1.2 e-commerce here.) We will be using a variety of tools, many builtin to Django. These are all relatively stable and mature, but as with all open source technology, new versions could change their usage at any time. Exposing data and APIs One of the biggest elements of the web applications developed in the last decade has been the adoption of so-called Web 2.0 features. These come in a variety of flavors, but one thing that has been persistent amongst them all is a data-centric view of the world. Modern web applications work with data, usually stored in a database, in ways that are more modular and flexible than ever before. As a result, many web-based companies are choosing to share parts of their data with the world in hopes of generating "buzz", or so that interested developers might create a clever "mash-up" (a combination of third-party application software with data exposed via an API or other source). These mash-ups take a variety of forms. Some simply allow external data to be integrated or imported into a desktop or web-based application. For example, loading Amazon's vast product catalog into a niche website on movie reviews. Others actually deploy software written in web-based languages into their own application. This software is usually provided by the service that is exposing their data in the form of a code library or web-accessible API. Larger web services that want to provide users with programmatic access to their data will produce code libraries written in one or more of the popular web-development languages. Increasingly, this includes Python, though not always, and typically also includes PHP, Java, or Perl. Often when an official data library exists in another language, an enterprising developer has ported the code to Python. Increasingly, however, full-on code libraries are eschewed in favor of open, standards-based, web-accessible APIs. These came into existence on the Web in the form of remote procedure call tools. These mapped functions in a local application written in a programming language that supports XML-RPC to functions on a server that exposed a specific, well-documented interface. XML and network transport protocols were used "under the hood" to make the connection and "call" the function. Other similar technologies also achieved a lot of use. For example, many web-services provide Simple Object Access Protocol (SOAP) interface, which is the successor to XML-RPC and built on a very similar foundation. Other standards, sometimes with proprietary implementations, also exist, but many new web-services are now building APIs using REST-style architecture. REST stands for Representational State Transfer and is a lightweight and open technique for transmitting data across the Web in both server-to-server and client-to-server situations. It has become extremely popular in the Web 2.0 and open source world due to its ease of use and its reliance on standard web protocols such as HTTP, though it is not limited to any one particular protocol. A full discussion of REST web services is beyond the scope of this article. Despite their simplicity, there can arise many complicated technical details. Our implementation in this article will focus on a very straightforward, yet powerful design. REST focuses on defining our data as a resource that when used with HTTP can map to a URL. Access to data in this scheme is simply a matter of specifying a URL and, if supported, any look-up, filter, or other operational parameters. A fully featured REST web service that uses the HTTP protocol will attempt to define as many operations as possible using the basic HTTP access methods. These include the usual GET and POST methods, but also PUT and DELETE, which can be used for replacement, updating, or deletion of resources. There is no standard implementation of a REST-based web service and as such the design and use can vary widely from application to application. Still, REST is lightweight enough and relies on a well known set of basic architectures that a developer can learn a new REST-based web service in a very short period of time. This gives it a degree of advantage over competing SOAP or XML-RPC web services. Of course, there are many people who would dispute this claim. For our purposes, however, REST will work very well and we will begin by implementing a REST-based view of our data using Django. Writing our own REST service in Django would be very straightforward, partly because URL mapping schemes are very easy to design in the urls.py file. A very quick and dirty data API could be created using the following super-simple URL patterns: (r'^api/(?P<obj_model>w*)/$', 'project.views.api')(r'^api/(?P<obj_model>w*)/(?P<id>d*)/$', 'project.views.api') And this view: from django.core import serializersdef api(request, obj_model, obj_id=None): model = get_model(obj_model.split(".")) if model is None: raise Http404 if obj_id is not None: results = model.objects.get(id=obj_id) else: results = model.objects.all()json_data = serializers.serialize('json', results)return HttpResponse(json_data, mimetype='application/json')) This approach as it is written above is not recommended, but it shows an example of one of the simplest possible data APIs. The API view returns the full set of model objects requested in JSON form. JSON is a simple, lightweight data format that resembles JavaScript syntax. It is quickly becoming the preferred method of data transfer for web applications. To request a list of all products, for example, we only need to access the following URL path on our site: /api/products.Product/. This uses Django's app.model syntax to refer to the model we want to retrieve. The view uses get_model to obtain a reference to the Product model and then we can work with it as needed. A specific model can be retrieved by including an object ID in the URL path: /api/products.Product/123/ would retrieve the Product whose ID is 123. After obtaining the results data, it must be encoded to JSON format. Django provides serializers for several data formats, including JSON. These are all located in the django.code.serializers module. In our case, we simply pass the results QuerySet to the serialize function, which returns our JSON data. We can limit the fields to be serialized by including a field's keyword argument in the call to serialize: json_data = serializers.serialize('json', results, fields=('name','price')) We can also use the built-in serializers to generate XML. We could modify the above view to include a format flag to allow the generation of JSON or XML: def api(request, obj_model, obj_id=None, format='json'): model = get_model(*obj_model.split()) If model is None: raise Http404 if obj_id is not None: results = model.objects.get(id=obj_id) else: results = model.objects.all()serialized_data = serializers.serialize(format, results)return HttpResponse(serialized_data, mimetype='application/' + format) Format could be passed directly on the URL or better yet, we could define two distinct URL patterns and use Django's keyword dictionary: (r'^api/(?P<obj_model>w*)/$', 'project.views.api'),(r'^api/(?P<obj_model>w*)/xml/$', 'project.views.api',{'format': 'xml'}),(r'^api/(?P<obj_model>w*)/yaml/$', 'project.views.api',{'format': 'yaml'}),(r'^api/(?P<obj_model>w*)/python/$', 'project.views.api',{'format': 'python'}), By default our serializer will generate JSON data, but we've got to provide alternative API URLs that support XML, YAML, and Python formats. These are the four built-in formats supported by Django's serializers module. Note that Django's support for YAML as a serialization format requires installation of the third-party PyYAML module. Building our own API is in some ways both easy and difficult. Clearly we have a good start with the above code, but there are many problems. For example, this is exposing all of our Django model information to the world, including our User objects. This is why we do not recommend this approach. The views could be password protected or require a login (which would make programmatic access from code more difficult) or we could look for another solution.
Read more
  • 0
  • 0
  • 3275