pinaxtutorial Documentation

Release 0.7.1

Paolo Corti

December 21, 2009

CONTENTS

1

Introduction 1.1 Intended audience . . . . . 1.2 What is Pinax . . . . . . . . 1.3 The Book Store application 1.4 Tutorial index . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

3 3 4 5 7 9 9 12 16 19 19 19 20 21 22 22 23 24 27 28 29 34 38 38 39 39 40 42 43 45 45 45 46 48 49

2

Installing Pinax and making basic customisation 2.1 Installing Pinax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Creation of the Pinax project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Making basic customisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Developing the basic application and plugging it in Pinax 3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . 3.2 Creating the application . . . . . . . . . . . . . . . . 3.3 Creating the models . . . . . . . . . . . . . . . . . . 3.4 A note about localization . . . . . . . . . . . . . . . . 3.5 Installing the application in the Pinax project . . . . . 3.6 Syncronizing the database . . . . . . . . . . . . . . . 3.7 Configuring the urls . . . . . . . . . . . . . . . . . . 3.8 Writing the views . . . . . . . . . . . . . . . . . . . . 3.9 Bookstore css and images . . . . . . . . . . . . . . . 3.10 Plugging the bookstore application into Pinax . . . . . 3.11 Writing the templates . . . . . . . . . . . . . . . . . 3.12 A quick tour of the basic bookstore application . . . . 3.13 What’s next . . . . . . . . . . . . . . . . . . . . . . . 3.14 Where can I get the code? . . . . . . . . . . . . . . . Internationalization of the application 4.1 Using translation strings in Python code and templates 4.2 Creating and compiling language files . . . . . . . . . 4.3 Changing settings . . . . . . . . . . . . . . . . . . . 4.4 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . Using avatars, pagination and profiles 5.1 Introduction . . . . . . . . . . . 5.2 Adding support for avatars . . . . 5.3 Adding support for pagination . . 5.4 Adding support for user profiles . 5.5 Notes . . . . . . . . . . . . . . .

3

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

4

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

5

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

i

6

Adding a comment system 6.1 Introduction . . . . . . . . . . . . . . . . . . . 6.2 Setup . . . . . . . . . . . . . . . . . . . . . . . 6.3 Using django-threadedcomments in the templates 6.4 How it works . . . . . . . . . . . . . . . . . . . 6.5 Notes . . . . . . . . . . . . . . . . . . . . . . . Indices and tables

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

51 51 51 51 53 54 55

7

ii

pinaxtutorial Documentation, Release 0.7.1

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License Index of tutorial:

CONTENTS

1

Release 0.pinaxtutorial Documentation.7.1 2 CONTENTS .

Linux/Unix. using these popular resources. If you want quickly enter Django and then Pinax you may try Instant Python.1. please don’t hesitate to put some comment in my blog’s posts: I will try to update the tutorial.1 If you are new to Python According to the Python web site “Python is a programming language that lets you work more quickly and integrate your systems more effectively.”. When I started. You can learn to use Python and see almost immediate gains in productivity and lower maintenance costs. 1. if you find errors or you have suggestions to give. But even if you are new to Python and Django. I highly recommend this excellent tutorial or the popular Dive Into Python book. 1. an open source platform for building Django applications. This is why I am going to write this tutorial. While I enjoyed a lot learning how to develop software with this framework. pragmatic design. and I am going to happily use it for a series of projects.NET virtual machines.2 If you are new to Django As written in the Django web site. I found a bit difficult to get documentation about it.1 Intended audience You may easily follow this tutorial if you have some Python and Django experience. 1. “Django is a high-level Python Web framework that encourages rapid development and clean.at this time) documentation on the project web site. Many of you will have heard about the Ruby on Rails web framework: we can confidently say that Django is to Python 3 . There is really a lot of documentation. While reading my posts.1. you may reasonably follow this tutorial picking a bit of Python and Django confidence from the following resources (note. I decided to write a test application for understanding the Pinax philosophy before going for real development projects. if not reading the source code and the (few . hoping it will be really useful for the Django/Pinax community. and has been ported to the Java and . trying to make it a good resource for people willing to learn to develop with Pinax.CHAPTER ONE INTRODUCTION In the last weeks I was studing Pinax .” If you are new to Python you can be quickly become productive with it. Python runs on Windows. however. that you should have programming experience and you should not be new to web development). I think it can be very useful for other developers new to Pinax to write down my experience. Mac OS X.

You may quickly get the a taste of Django. and sorting links generation.Django provides an object-relational mapper. like blogs. for example photo that are considered inappropriate.1 what Ruby on Rails is to Ruby. Windows Local Live (Virtual Earth). geocoder. a powerful template system.” When you are developing a web site. • locations.7. This is the idea behind the Pinax Project. an elegant URL design system. let users to ask friendship from other users or from people external to the site. helping the developers to write web applications in an agile manner. these are some of the applications included in Pinax that you could use for your web development: • ajax_validation. Yahoo! Maps. GeoNames. 1. gives to Pinax openid support. • gravatar. Release 0. originally named Django Hot Club like the jazz group founded in France by Django Reinhardt (that gives its name to Django): following the DRY principles. • announcements. if you choose Django as the web framework you have already a lot of goodness that make your work a lot easier than with other web frameworks. Django promotes the DRY principles. and Semantic MediaWiki pages.2 What is Pinax According to the Pinax web site: “Pinax is an open-source platform built on the Django Web Framework. MediaWiki pages (with the GIS extension). tagging systems and so on and it would be crazy to design and develop them from scratch over and over again. • django_openid. gives the users the possibility to flag contents. Shortly. • blog. 4 Chapter 1. By integrating numerous reusable Django apps to take care of the things that many sites have in common. allow users to manage avatars for their profile. using the famous Django’s tutorial. If you want to master Django you should read the excellent documentation. for letting the users to use their gravatar as avatar. Used from the locations application.but of course in a different fashion . gives you the ability to manage announcements and to broadcast them into your site (keeping track in session of already displayed ones) or by emailing users.pinaxtutorial Documentation. let users manage bookmarks. • friends. and other goodness that a modern web framework should provide. • geopy. it’s for cases where you don’t want to require an email address to signup on your website but you do still want to ask for an email address and be able to confirm it for use in optional parts of your website. Like Ruby on Rails. Pinax try to make you re-use software in the smartest way. Introduction . wikis. • emailconfirmation. allow easy sorting objects list. • django_sorting. it lets you focus on what makes your site different. and come back to the Pinax tutorial. • bookmarks. a simple application for performing ajax validation of forms created using Django’s forms system based on jQuery. But many web sites have many common elements. an impressive cache system. a blog application. a geocoding application for geocoding addresses from Google Maps. • avatar. Like Ruby on Rails . gives the user the ability to put geo-locate himself at any time. the Pinax Project is a collection of Django application you should use in your web projects for not starting from scratch every time. • flag. photo galleries.us.

• wiki.3.3 The Book Store application The aim of this tutorial is to teach you Pinax (and Django) with an hands on project. • photologue. 1. • tribes. So thanks to the smart developers of these applications! To get a quick idea of the tutorial final’s result. • pagination. an interest groups management application.1 • mailer. Markdown. • vobject. a photo management applications. • uni_form. The Book Store application 5 . let the user to vote content in a reddit-like fashion. let the user to tag any kind of content (ex: a blog post). for time zone calculations. a wiki application for your site. Users may create photo galleries. you may have a look at the book store application we will develop: here is a live instance (you need to register to access it). • robots. the popular syntax highlighter (to be used. following the best practices used from other Pinax projects. • tagging. provide a simple tag and/or filter that lets you quickly render forms in a div format. like Flickr or YouTube. The user can then browse content by tag. gives the user the possibility to send messages to other users. • messages.pinaxtutorial Documentation. Each user is provided with a message box where messages can be kept or deleted. is a Python package for parsing and generating vCard and vCalendar files. Release 0. for letting a user to swap something with another user. • pytz. • voting. where users belonging to that group may take part to topics. for managing web robots access rules to your site. a project application with task and issue management. a collection of utilities for text-to-HTML conversion. • template_utils. to the microblogging application. for example. • notification. • oembed. We will build a real application: a book store component for Pinax. and to other ones. • threadedcomments. 1. In fact you will find in the book store application many similiar elements to the bookmarks application. Supported format are Textile. and associate them to other contents. for example. Note that for developing the book store application I was largely inspired by other Pinax applications. • swaps.7. and gives Pinax the ability for example to import contact from GMail or Yahoo. a notification framework. in the wiki and in the blog application). • projects. reStructuredText (to be used. • pygments. even in a threaded way. a twitter clone. gives the site oembed support. let the user to write comments on content. in the wiki and in the blog application). • microblogging. for allowing an embedded representation of a URL on third party sites. let the developer to easily paginate objects list. gives you the ability to queue mail messages and notifications for asynchronous delivery.

• users can vote for a book in a reddit-like fashion. • users can access RSS feeds of book lists (global list and per user list). These are the user stories of the book store application we want to build: • for every book we want to store the following attributes: title. • a user can flag a book added by another user as inappropriate (and an administrator may remove it later). • user profile section must provide a book section with every book added by the profile’s user. Comments can be threaded.1 We want to build a Pinax application to manage the books of a book store (something like in the Amazon fashion). • users can comment on a book. description. • users can add books to the store. Release 0. • a user must be notificated (optionally via email) every time a comment is made on a book he has added. • users can update and delete their books. • books browsing must provide pagination. • users can browse all of the books. author. Introduction . • every book must show which user has added and its avatar (or gravatar if the user has one).pinaxtutorial Documentation. 6 Chapter 1. • the application can be easily localized in different languages to be used in any country.7. • books can be browsed by user and by tag. publisher. tags. cover art.

7. Release 0.1 1.pinaxtutorial Documentation. as often as i will have the time to post): • Installing Pinax and making basic customisation • Create the book store django’s application and plugging it into Pinax • Using pagination.4. avatars and profiles • Using the voting application • Using the tagging application • Using the feeds application • Enabling threaded comments for the book store application • Implementing notifications • Using the flag application • Deploying Pinax Time to start the Pinax Tutorial! 1.4 Tutorial index This is the planned tutorial index (there will be a blog post for each paragraph in the next days. Tutorial index 7 .

pinaxtutorial Documentation. Introduction .1 8 Chapter 1. Release 0.7.

If you are using another Ubuntu version or a different Linux distribution.com/Pinax-0. For Windows please refer to the Pinax official site or .04 Virtual Machine.1.10.04 box. You will install and use for this tutorial Pinax v0. Ubuntu 9.1. • Python Imaging Library (PIL). to make things even easier.1 on a Ubuntu 9.1-bundle. but this procedure .1 (latest release at the date of this post). 2. the release bundle has everything you need for running Pinax. should work well on every Linux box.tar. First create a directory named virtualenv.6 and SQLite 3.1 Installing Pinax 2. then download the tar. What is not included is: • Python.7.7.pinaxproject. • SQLite.tar. so you will be able to follow step by step this tutorial. If you want to know more about virtualenv take a look at the official documentation.04 includes Python 2.gz 2.CHAPTER TWO INSTALLING PINAX AND MAKING BASIC CUSTOMISATION I will assume you are installing Pinax v0.1.7.2 Creation of the virtualenv The best way to try (and to develop with) Pinax is to use virtualenv.gz paolo@ubuntu:~/virtualenv$ tar zxf Pinax-0.1 Download Pinax First step for installing Pinax is to download it.1-bundle. and to create an Ubuntu 9. PIL 1.with a few modifications.6. please verify to have all of this software. so you have everything. As suggested from the official installation procedure. In short words here I can say that what virtualenv does (and does it well!) is creating isolated Python environments.6.gz bundle and extract it in that directory paolo@ubuntu:~/virtualenv$ wget http://downloads.rather I highly reccomend to use VirtualBox. There are 3 main benefits using virtualenv: 9 .7. There are ready images like this one.

naming it myenv: (pinax-env)paolo@ubuntu:~/virtualenv$ virtualenv --python=python2.3. Pinax or whatever other Python Packages using the Python on the system (everything would be installed in /usr/lib/python2. Plus. 01:56:41) [GCC 4.04 installation. in <module> ImportError: No module named django Now activate the virtualenv you have just created.5.1 and ipython in myenv. "credits" or "license" for more information.1 • It is impossible to create different environments with different versions of Django. ’final’. First you may probably need the virtualenv command.5. 0) 10 Chapter 2.for example in a shared host . and you will be able to use the easy_install command to install Python packages in your virtualenv in a breeze.6. Activating a virtualenv is easily done by typing: (pinax-env)paolo@ubuntu:~/virtualenv$ cd myenv/ (pinax-env)paolo@ubuntu:~/virtualenv/myenv$ source bin/activate Now install django 1.6. Let’s see a concrete example: you are going to create a virtualenv with Python 2..5 myenv If you are on a scratch Ubuntu 9. 1. plus the default Python is version 2. >>> import django Traceback (most recent call last): File "<stdin>".2. In [1]: import django In [2]: django. To run ’ipython’ please ask your administrator to bash: ipython: command not found paolo@ubuntu:~/virtualenv/myenv$ python Python 2. 0.4 (r254:67916.1: (myenv)paolo@ubuntu:~/virtualenv/myenv$ ipython Python 2. if you have never used.5/sitepackages and you could not install two different versions of the same component) • You may be interested to install an application and to leave it in that situation forever..1 and IPython (if you are new to Python you may wonder about what IPython is: a very complete article describing IPython is here). Apr 4 2009.djangoproject. by using the easy_install command: (myenv)paolo@ubuntu:~/virtualenv/myenv$ easy_install http://www. . To prove this just look the following: paolo@ubuntu:~/virtualenv/myenv$ ipython The program ’ipython’ is currently not installed. it includes the excellent Setuptools. IPython and Django are not available. line 1.7.com/download/1. Apr 19 2009.1/tarbal (myenv)paolo@ubuntu:~/virtualenv/myenv$ easy_install ipython Now you are able to use ipython and you can succesfully import Django 1. "credits" or "license" for more information. so using it is definitely a good idea. For installing it (on Debian and Ubuntu): (pinax-env)paolo@ubuntu:~/virtualenv$ sudo apt-get install python-virtualenv Now you can create the virtualenv. without updating any components on which the application is based • You may not have .the privileges to install packages in site-packages directory Virtualenv solve all this problems.pinaxtutorial Documentation. 17:55:16) Type "copyright". Installing Pinax and making basic customisation .2 (release26-maint. Django 1.VERSION Out[2]: (1. Release 0. "copyright".3] on linux2 Type "help".

in the site-packages there is the Pinax directory. now I make some considerations about the site-packages directory: as you have seen a few lines above.5.1. like for example the bookmarks. the default Python here is 2. the mailer and the swaps applications. Installing Pinax 11 .egg setuptool Now that you understand what a virtualenv is.egg setuptools-0.py . and you will name it pinax-env. ’final’) 2. but everything is under the site-packages directory of the virtualenv: (myenv)paolo@ubuntu:~/virtualenv/myenv/lib/python2. 0. ls lib/python2. Release 0.py ..egg-info django_microblogging-0.7.egg easy-install.1-bundle$ python scripts/pinax-boot.6c9-py2. |-.3-py2.1 Note that the IPython is now installed. There are two main places where Pinax live: the site-packages directory of your virtualenv and the project directory. you are ready to create the virtual environment.7. This is its structure (we show only 2 levels here): paolo@ubuntu:~/virtualenv/pinax-env/lib/python2.pinaxtutorial Documentation.5/site-packages$ ls Django-1. 7.authsub | |-../pinax-env/ paolo@ubuntu:~/virtualenv/pinax-env$ source bin/activate Note now what is in the virtualenv site-packages directory (tons of useful stuff. this directory contains a ton of Python packages that are included in Pinax: you will find there most of the applications and packages we have been talking in the introduction.6.analytics | |-.6/site-packages/pinax$ tree -d -L 2 .1. this is the Pinax core!): (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env$ ajax_validation announcements atom atomformat.7.3 The Pinax directory structure Let’s spend just a few lines about the Pinax directory structure..account | |-.1.5. You will see later the project directory structure.1-bundle/ paolo@ubuntu:~/virtualenv/Pinax-0.10-py2. You can easily check that nothing has been written to the /usr/lib/python2.6.4. 3.2-py2.autocomplete_app 2.2-py2. 0.pth ipython-0. Also. 0) import pinax pinax.6.1-bundle$ cd .1-py2.VERSION (1.apps | |-.5/site-packages directory.6/site-packages/ django_markup django_markup-0.7.1. and then activate it: paolo@ubuntu:~/virtualenv/Pinax-0.0 is available..4.egg-info django_messages-0. ’final’. and the Django version 1.egg-info Pi pi py Py To be sure that everything is fine. you may try if your virtualenv can import Django and Pinax: In [1]: In [2]: Out[2]: In [3]: In [4]: Out[4]: import django django./pinax-env Wait a while while the virtualenv is created.VERSION (0. For doing so you will use a python script included in the Pinax bundle instead than the virtualenv command: paolo@ubuntu:~/virtualenv$ cd Pinax-0.5.5.

pinaxtutorial Documentation.waitinglist core |-.templatetags utils A few notes: some of the applications.tribes |-.projects |-.bbauth |-.tasks |-. and they are in the apps directory. Installing Pinax and making basic customisation .default middleware projects |-. using the pinax-admin clone_project. are developed directly in the Pinax packages (at least at this time). available to you in your virtualenv.photos |-.profiles |-.intranet_project |-.cms_project_company |-. Release 0. called default. 2.signup_codes |-.topics |-.serializers fixtures ‘-.code_project |-. To see a list of available existing projects. Here the way to go is to clone one of the existing Pinax templates projects.2 Creation of the Pinax project Now it is time to create a Pinax project.1 | | | | | | | | | | | | | | | |-| | |-| |-| |-|-| | | | | | | | |-| |-| ‘-- |-.basic_profiles |-.blog |-.groups |-.basic_project |-.voting_extras ‘-. but basically for starting you will just need to copy one of them). Soon we will see how we can customise the templates.default templatetags ‘-. use the -l option like this: 12 Chapter 2.management ‘-.threadedcomments_extras |-. The media directory contains all of the css and images needed by Pinax and by its applications. The projects directory contains the template projects you may use to not start from scratch a Pinax project (more in the next paragraphs about this.social_project templates ‘-. like the blog. the profile and the projects ones.sample_group_project ‘-.7.cms_project_holidayhouse |-. The templates directory contains the Pinax themes: at this time there is only one available theme (more are coming in the future).generate media ‘-.tagging_utils |-.private_beta_project |-.

templates and content including in the project demonstrate a basic site for holiday house rentals. swaps. You will clone the social_project. In 0. Take a while for reading about all the templates project that are provided by Pinax. code_project: This project demonstrates group functionality and the tasks. right in the frontend of the site. It is intended to be the starting point for things like code project management where each code project gets its own wiki. The sample media. including images. bookmarks. The sample media. social_project: This project demonstrates a social networking site. tribes. blogs.7. The easiest and minimal way to start a Pinax project would be to start from the basic_project. It includes no extra tabs. It provides a top-level task tracking system. which show different membership approaches and content apps.5 this was called "complete_project". Creation of the Pinax project 13 . It is intended to be the starting point of sites like intranets. tribes and projects. wiki and bookmarks. Otherwise it is the same as basic_project. tweets. From here you can add any extra functionality and applications that you would like. photos. cms_project_holidayhouse: A very simple CMS that lets you set up templates and then edit content. private_beta_project: This project demonstrates the use of a waiting list and signup codes for sites in private beta. basic_project: This project comes with the bare minimum set of applications and templates to get you started.2. so we will start from the social_project. only the profile and notices tabs are included by default. task tracking system and threaded discussions. Release 0. wiki and topics apps. It provides profiles. friends.pinaxtutorial Documentation. But here we want to see more Pinax stuff in action. templates and content including in the project demonstrate a basic company website.1 (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env$ pinax-admin clone_project -l Available Projects -----------------sample_group_project: This project demonstrates group functionality with a barebones group containing no extra content apps as well as two additional group types. locations and user-to-user messaging. cms_project_company: A very simple CMS that lets you set up templates and then edit content. right in the frontend of the site. creating a project named pinaxtutorial: 2. wikis. intranet_project: This project demonstrates a closed site requiring an invitation to join and not exposing any information publicly. including images.

Message model Installing index for notification.com Password: Password (again): Superuser created successfully.6/site-pack Installing json fixture ’initial_data’ from ’/home/paolo/virtualenv/pinax-env/lib/python2. Would you like to create one now? (yes/no): yes Username (Leave blank to use ’paolo’): E-mail address: pcorti@gmail. of course): (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env/pinaxtutorial$ sqlite3 dev. for example the really excellent Postgres): (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env$ cd pinaxtutorial/ (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env/pinaxtutorial$ chmod 777 manage.10 Enter ". all the tables needed from Pinax and Django have been created.7.1 (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env$ pinax-admin clone_project social_project pinaxtutoria Finally you need to sync the project with the database (we are using the default database engine.2. when syncing the database for the first time. Installing Pinax and making basic customisation . Release 0. I created a superuser named like me.py (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env/pinaxtutorial$ . all the tables just created are listed. which means you don’t have any superusers defined..py syncdb Creating table auth_permission Creating table auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site Creating table notification_noticetype Creating table notification_noticesetting .. You just installed Django’s auth system.Permission model Installing index for auth.pinaxtutorial Documentation. Installing json fixture ’initial_data’ from ’/home/paolo/virtualenv/pinax-env/lib/python2. 2.db SQLite version 3." sqlite> select * from sqlite_master.py database section and choose another database../manage. Sqlite.NoticeSetting model .. Installing index for auth.6. For example. you are asked to create the superuser for your application. Also. You can easily test this by querying the sqlite_master table (if you are using that engine.help" for instructions Enter SQL statements terminated with a ". but if you wish you may change the settings.6/site-pack Installed 18 object(s) from 2 fixture(s) So.1 First look at the Pinax project Now you are ready to start and try the project we just created: 14 Chapter 2. using the sync option of the django-admin command.

1 (pinax-env)paolo@ubuntu:~/virtualenv/pinax-env/pinaxtutorial$ .7. using settings ’pinaxtutorial.0.py runserver Validating models. 0 errors found Django version 1.0.. Now if you type in the brower http://localhost:8000.pinaxtutorial Documentation.1:8000/ Quit the server with CONTROL-C../manage. your will access the Pinax project home page: Now try to register a user by going to the signup page: http://localhost:8000/account/signup/ 2.settings’ Development server is running at http://127. Release 0.2.3. Creation of the Pinax project 15 .0.

"templates". Installing Pinax and making basic customisation .join(PROJECT_ROOT. ) in my Ubuntu box. 16 Chapter 2. Keep in mind that.1 After registering the user try uploading a photo: http://localhost:8000/photos/upload/ and try to add some test comment to it: Now take some more time to learn what the pinax social_project offers: there is a ton of stuff already set to be used in your production environment.join(PINAX_ROOT. Release 0. I will refer to this two directory as PROJECT_ROOT and PINAX_ROOT in the following sections. according to the settings. and by the authentication system. you are going to make the last little step at this time: you will learn how easy is in Pinax to make (very) basic customisation. for obvious reasons. storing your basic customisation by modifying the templates in the PINAX_ROOT would not be a good choice: as soon as you would decide to update your Pinax installation with a new release of Pinax or from new updates from the trunk if you are living on the edge using the Pinax development version. For the sake of brevity. PINAX_THEME).path. as with many pythonic things. the templates directories are in the project directory: ~/virtualenv/pinax-env/pinaxtutorial and in the pinax directory: ~/virtualenv/pinax-env/lib/python2. bookmarks.py of the project you created. os.7. your html modified templates would be replaced by the new ones and you would miserably loose your customisation. Also be delighted by the production-ready messaging system. Have fun digging the profiles. tweets.3 Making basic customisation Now that you are ready with your Pinax environment. tribes.6/site-packages/pinax. blogs. "templates"). Now.pinaxtutorial Documentation. 2.path.py) TEMPLATE_DIRS = ( os. The best way to go. templates are loaded from two different directories: (settings. is to override the templates of the PINAX_ROOT templates directory with the templates of the PROJECT_ROOT templates directory. if you wish. swaps and locations sections.

py file: (PROJECT_ROOT/urls.html"}.com/lab/icons/silk/">Silk icon set 1. direct_to_template. According to what we have written a few lines before. name="dmca"). direct_to_template.html"}. name="privacy").html template for modifying your about page. 2.with little modifications . {"template": "about/terms.html"}.pinaxtutorial Documentation.3. direct_to_template. {"template": "about/what_next.html"}. There is. Suppose you want to change the text of the about page (it is here: http://localhost:8000/about/). Release 0. url(r’^terms/$’.html: your project is feeding the about view by that file. url(r’^privacy/$’.html file): {% {% {% {% extends "site_base. you DO NOT change this file. Making basic customisation 17 . direct_to_template. url(r’^dmca/$’.html template you created in the PROJECT_ROOT/templates/about directory. name="about"). According to the central urls.7. But you override it recreating this file in your PROJECT_ROOT/templates/about directory. But wait! there is not the PROJECT_ROOT/templates/about/about. url(r’^what_next/$’. name="what_nex ) It is easy to understand that you need to change the about/about. rendered from the about.urls’)).the PINAX_ROOT/templates/default/about/about. direct_to_template. instead. So this is what you have to do: first create the PROJECT_ROOT/templates/about/about. {"template": "about/privacy.html template. {"template": "about/about.py file: urlpatterns = patterns(’’. include(’about. The urls for the about/ views of our project are included in the PROJECT_ROOT/apps/about/urls.1 Let’s see a concrete sample. url(r’^$’.html"}.html" %} load i18n %} block head_title %}{% trans "About" %}{% endblock %} block body %} {% blocktrans %} <p>My new <b>About Page</b></p> {% endblocktrans %} {% blocktrans %} Pinax includes the <a href="http://www.html template file.py) (r’^about/’.3</ {% endblocktrans %} {% endblock %} If you now go to: http://localhost:8000/about/ you will see your new about page. name="terms"). {"template": "about/dmca. the PINAX_ROOT/templates/default/about/about. Then put this few lines in it (I am copying .famfamfam.

1 18 Chapter 2. Installing Pinax and making basic customisation .pinaxtutorial Documentation.7. Release 0.

py command: chmod 777 manage. And you are goint to plugin this basic application into Pinax.py startapp bookstore Now that you have created the application. 3. 19 . Delete) features./manage. After finishing with this part you will have the core of the bookstore application working as desired. voting. notifications. give execute permissions to the manage.2 Creating the application Before doing anything. Read. and flags for contents. avatars.CHAPTER THREE DEVELOPING THE BASIC APPLICATION AND PLUGGING IT IN PINAX 3. installing it in the Pinax project and syncing the database.1 Introduction In this part of the tutorial you are going to create the core of the bookstore application. tagging. pagination. it it time to add the models. Update.py Now create the bookstore application: . comments. feeds. but basically this part is the most important one and it is the way you can create from scratch an application and make it enabled for Pinax. You will be able to: • see a list with all the books in the bookstore • add a new book • update and delete your books • see a list of all books added by you • see a list of all books added by a user In the following parts you will add some more goodness like localization. profiles. with all the pages that gives access to the CRUD (Create.

3 Creating the models For creating the models you need to edit the models. author.coverart: return ’#’ upload_to = path. def get_thumb_url(self): return self. """ if not self. [self.ForeignKey(User._get_thumb_url(’thumb_100_100’. ) def _get_thumb_url(self.path) tiny = path. max_length=255) author = models.open(self. path.thumbnail(size. named Book.pk]) get_absolute_url = models. folder.models import User from django.auth. verbose_name=_(’adder’)) added = models.path)). max_length=255) publisher = models. path. Release 0.CharField(_(’author’). blank=True. folder.coverart.basename(self.coverart.DateTimeField(_(’added’). added """ title = models. Image. folder.py # python import os from os import path from datetime import datetime # django imports from django.contrib.7.translation import ugettext_lazy as _ class Book(models.join(path. null=True) adder = models. coverart.1 3.ANTIALIAS) im. PROJECT_ROOT/bookstore/models. publisher.pinaxtutorial Documentation. default=datetime. description. max_length=255) description = models.dirname(self.100)) 20 Chapter 3.basename(self. (100.coverart.CharField(_(’publisher’).coverart.permalink(get_absolute_url) def __unicode__(self): return self. blank=True) coverart = models. Developing the basic application and plugging it in Pinax .normpath(tiny) if not path.save(tiny.now) def get_absolute_url(self): return ("describe_book".py that has been created for you when creating the application.CharField(_(’title’). adder.db import models from django.path)) tiny = path. size): """ get a thumbnail giver a folder and a size. ’JPEG’) return path.utils.dirname(self.exists(tiny): import Image im = Image.TextField(_(’description’).Model): """ Book Model: title.path) im.url).coverart. Our application will be composed by a single model.ImageField(upload_to="bookstore".conf import settings from django. related_name="added_books".title class Meta: ordering = (’-added’.join(upload_to.

author.get_thumb_url() if link is None: return ’<a href="#" target="_blank">NO IMAGE</a>’ else: return ’<img src=%s />’ % (link) thumb.4. named id. self. added • Also an identifier field. description. publisher.allow_tags = True def fullpicture(self): """ Get full picture <a>.4 A note about localization One of the aims of this tutorial is also to make the developer confident with the powerful Django’s localization features.models import Book class BookAdmin(admin.coverart) if link is None: return ’<a href="#" target="_blank">NO IMAGE</a>’ else: return ’<img src=%s />’ % (link) thumb. Release 0.py from django.py file like this one: PROJECT_ROOT/bookstore/admin. BookAdmin) 3.translation • in the templates you will use the {% blocktrans %} block 3. coverart.register(Book.allow_tags = True A few notes about the Book’s model: • The basic application of the tutorial implements these fields: title.models This is why you need to import User from • The default ordering will be based on the time each book has been added.utils. will be created by Django behind the scenes • The adder field is a foreign key to the user table. create an admin. adder. ’added’. ’publisher’. ’coverart’) admin.7. """ link = "%s%s" % (settings. A note about localization 21 . Meanwhile just be aware that we will make the strings of the application easily translatable by using two mechanism: • in the models (as you may have noticed) you will use the ugettext_lazy class from django. django.pinaxtutorial Documentation. One of the part of the tutorial will teach you how to develop a localization-ready application.contrib import admin from bookstore.MEDIA_URL.1 def thumb(self): """ Get thumb <a>.site.ModelAdmin): list_display = (’title’.auth. from the newest to the oldest • The thumb method returns the url of the thumbnail of the coverart • The fullpicture method returns the url of the coverart If you wish that the bookstore application may be managed also from the Django Admin application (this is mainly useful for letting the system administrator to interact with the system).contrib. ’description’. ’adder’. """ link = self.

"coverart" varchar(100).py file. ’account’. . Developing the basic application and plugging it in Pinax . # internal (for now) ’analytics’. ’profiles’.py syncdb Note that only a new table is generated.contrib. Release 0. # add this line # my apps ’bookstore’.5 Installing the application in the Pinax project Add the Bookstore application in the settings.7. This is the SQL that has been ran by syncdb: CREATE TABLE "bookstore_book" ( "id" integer NOT NULL PRIMARY KEY..auth’.. "publisher" varchar(255) NOT NULL.pinaxtutorial Documentation. # also add this line ) 3. "author" varchar(255) NOT NULL. MySql. and its named bookstore_book. "adder_id" integer NOT NULL REFERENCES "auth_user" ("id").. the SQL may be slightly different.. "description" text NOT NULL.admin’..contrib. .py INSTALLED_APPS = ( # included ’django. ’django./manage. . Do the same with the Admin application if you want to manage the bookstore application also from there: PROJECT_ROOT/settings. you need to syncronize the database: .. if you are using a different database like Postgres.1 3. # must be first ’django_openid’.6 Syncronizing the database Now that you created a new model..contrib.contenttypes’. Time to run the server and test your new application: 22 Chapter 3. # external ’notification’. "title" varchar(255) NOT NULL. ’django. "added" datetime NOT NULL ) Consider that I am using Sqlite.. ’emailconfirmation’.

so keep going with the tutorial.7 Configuring the urls Configuring the urls means to design how to map urls to pages.pinaxtutorial Documentation. at: http://localhost:8000/admin you will be able to manage your bookstore with basic CRUD pages.1 . Configuring the urls 23 . given its identifier: http://localhost:8000/bookstore/4/update/ (it this case the book with id=4) 3. For the Bookstore application this is what is planned to be: • A page (the home page of http://localhost:8000/bookstore/ the bookstore application) for getting a list of all books: • A page for getting a list of your books: http://localhost:8000/bookstore/your_books/ • A page for getting a list of the http://localhost:8000/bookstore/user_books/an_user/ books added by a different users: • A page for adding a book: http://localhost:8000/bookstore/add/ • A page for viewing a book. given its identifier: http://localhost:8000/bookstore/4/book/ (it this case the book with id=4) • A page for updating a book. Any web developers with good habits should plan the pages composing the application that is developing. To integrate this CRUD pages into Pinax. 3./manage. and mapping them to corresponding urls.py runserver Now if you access the admin interface.7. Release 0. you are going to write the views of these pages in the next sections.7.

This is where to add the file in the urls.views. ’bookstore. (r’^feeds/bookmarks/(.py project file: PROJECT_ROOT/urls.models import Book urlpatterns = patterns(’’.py file.your_books’.views.feed’. ’bookstore. tweets_feed_dict). Instead than adding these mappings to the central urls.delete_book’.contrib. (r’^feeds/posts/(.book’.books’. name="describe_book"). url(r’^(\d+)/delete/$’. bookmarks_feed_dict).urls’)). Now you need to include this directory in the project urls.py 24 Chapter 3..*)/?$’.views. name="your_books"). you add the mappings to the views in the urls. ’bookstore.pinaxtutorial Documentation.syndication. ) A few notes about the urls: • each url maps a uri (in a regular expression form) to a Django view. Developing the basic application and plugging it in Pinax . name="update_book"). ’bookstore.urls.feed’.py file (r’^bookstore/’. These parameters are passed to the view 3. . ’bookstore. ’django. For example in the case of the url named your_books the request made to Django will be managed by a view named your_books • note that in some case there is a parameter (an integer or a string) in the regular expression: that is for the identifier of a book or for the name of the user.update_book’.views.py file you need to create in the application directory that translate to django the mappings we have planned before: PROJECT_ROOT/bookstore/urls.defaults import * # from bookstore from bookstore. it is time to actually write them! PROJECT_ROOT/bookstore/views. url(r’^(\d+)/update/$’. for clearity you create a urls.syndication.py urlpatterns = patterns(’’.contrib.py file of the project.py file. ’bookstore.views. ’django.views. include(’bookstore.1 Now that we planned the urls needed by the bookstore application.views.. url(r’^$’. url(r’^user_books/(?P<username>\w+)/$’. # CRUD urls url(r’^add/$’.add_book’.syndication. ’django. (r’^feeds/tweets/(.*)/$’. ) and this is the urls. name="user_books"). Release 0.7. blogs_feed_dict). url(r’^(\d+)/book/$’.py #from django from django.views.conf.py file in the bookstore application directory. url(r’^your_books/$’.views. name="delete_book").*)/$’. ’bookstore. name="add_book").contrib.user_books’. # bookstore urls. name="all_books").8 Writing the views Now that you have planned all the views composing the application.feed’.views.

}.objects. context_instance=RequestContext(request)) def user_books(request.objects.POST. { "books": books.http import HttpResponseRedirect from django.objects. context_instance=RequestContext(request)) @login_required def add_book(request): """ Add a book to the bookstore.adder: isyours = True return render_to_response("bookstore/book.shortcuts import render_to_response. "isyours": isyours. "list": ’all’.html". { "books": yourbooks.7. }.contrib. book_id): """ Return a book given its id.utils. "list": ’yours’. username): """ Return an user books list.models import User #from bookstore from bookstore.order_by("-added") return render_to_response("bookstore/books.html".translation import ugettext_lazy as _ from django. "list": ’user’.auth. context_instance=RequestContext(request)) @login_required def your_books(request): """ Return the logged user books list.html".urlresolvers import reverse from django.filter(adder=user).order_by("-added") return render_to_response("bookstore/books. username=username) userbooks = Book.filter(adder=request.contrib.auth. request.pinaxtutorial Documentation. get_object_or_404 from django. "username": username.order_by("-added") return render_to_response("bookstore/books. }. }. """ isyours = False book = Book.1 #from django from django. { "books": userbooks.all(). ordered by added date.html". """ user = get_object_or_404(User. Release 0. { "book": book.FILES) if book_form. """ yourbooks = Book.8.user == book.forms import BookForm def books(request): """ Return the all books list.decorators import login_required from django.user).models import Book from bookstore.core. context_instance=RequestContext(request)) def book(request. """ books = Book.is_valid(): 3. """ # POST request if request.get(id=book_id) if request.template import RequestContext from django. Writing the views 25 .objects.method == "POST": book_form = BookForm(request.

request.views. For 26 Chapter 3.pinaxtutorial Documentation.books")) # GET request else: book_form = BookForm() return render_to_response("bookstore/add. book • some of the views need authentication to the system: your_books. update_book. update_book. For example add_book. context_instance=RequestContext(request)) # generic case return render_to_response("bookstore/add. delete_book need a book_id parameter to know which book to process • all of the views define a response defined by a template and some variable that the template must process. }.save() request. Developing the basic application and plugging it in Pinax .delete() request.is_update = True if request. context_instance=RequestContext(request)) {’title’: @login_required def update_book(request. In this case you need to use the @login_required decorator • some of the views have additional input parameter to the request. set_trace() if book_form.create(message=_("You have saved book ’%(title)s’") % return HttpResponseRedirect(reverse("bookstore. Release 0.message_set.create(message=_("You have updated book ’%(title)s’") % return HttpResponseRedirect(reverse("bookstore.adder = request. add_book.save(commit=False) new_book.user == book.html".message_set.adder: #from ipdb import set_trace.user new_book.save() request.7. { "book_form": book_form.user. context_instance=RequestContext(request)) @login_required def delete_book(request.views.html".method == "POST": book_form = BookForm(request.user == book. """ book = Book.1 # from ipdb import set_trace. }. { "book_form": book_form. delete_book.user. id=book_id) if request.user. instance=book) book_form. }.html". { "book_form": book_form. set_trace() new_book = book_form.create(message="Book Deleted") return HttpResponseRedirect(reverse("bookstore.is_valid(): book_form.message_set.adder: book.FILES. user_books.get(id=book_id) if request. book_id): """ Update a book given its id.objects.books")) {’t Some notes on the views.POST.py file you just created: • some of the views can be accessed without authenticating to the system: books. "book": book.books")) else: book_form = BookForm(instance=book) return render_to_response("bookstore/update. """ book = get_object_or_404(Book. book_id): """ Delete a book given its id.views.

is_update = False def clean(self): """ Do validation stuff. ’author’.9.__init__(*args.ValidationError(_("There is already this book in the bookstore.html template and these variables processed by the response: books.cleaned_data class Meta: model = Book fields = (’coverart’. ’tags’) Here the form is generated by the model (DRY. ’title’. *args. At this time we do not want a book to be created (or updated) if: • title is empty • there is already a book with that title It is now time to write the application templates.count() > 0: raise forms. **kwargs): super(BookForm. self).cleaned_data[’title’]). list. if not self.models import Book class BookForm(forms.cleaned_data: return # if a book with that title already exists. Bookstore css and images 27 . Note that the clean method implements some validation stuff. before writing the templates.1 example the user_books renders the response with the books. it is finally time to plugin the Bookstore application into Pinax! 3.py #from django from django import forms from django. ’description’.py file and to add the BookForm that is used from the add_book and update_book views: PROJECT_ROOT/bookstore/forms.7. Don’t Repeat Yourself!).utils.is_update: if Book. """ # title is mandatory if ’title’ not in self.ModelForm): """ Book Form: form associated to the Book model """ def __init__(self. **kwargs) self..translation import ugettext_lazy as _ #from bookstore from bookstore.css file in the css directory like this one: PROJECT_ROOT/media/bookstore/css/bookstore. but before doing so let’s fix the way the Bookstore application css and images are managed. Inside the bookstore directory create a css directory and an img directory.pinaxtutorial Documentation. username Note that you also need to create a forms.objects. ’publisher’.9 Bookstore css and images Create a bookstore directory in the PROJECT_ROOT/media directory. Create a bookstore.")) return self.css 3.. Also.filter(title=self. Release 0.

Release 0.url { color: #666.css" /> }}pinax/css/friends.vote { width: 80px.autocomplete.css" /> }}pinax/css/locations.css and the bookstore application (you just need to add two lines): PROJECT_ROOT/bookstore/templates/bookstore/site_base.css" /> }}pinax/css/pagination. font-size: 90%.bookstore .narrow { width: 500px.1 /* BOOKSTORE */ table.css" /> }}pinax/css/avatar.css" /> 28 Chapter 3.html to include the the bookstore.bookstore td { vertical-align: top.here you insert the boookstore css--> }}css/site_tabs. } . } table. text-align: center.css" /> }}pinax/css/jquery. } . you just need to modify site_base.css" /> }}pinax/css/microblogging.7. font-style: italic.css" /> }}pinax/css/blogs.css" /> }}pinax/css/photos. vertical-align: middle.bookstore . } 3. } div. } table. Developing the basic application and plugging it in Pinax .css" /> }}pinax/css/messages. padding: 0.css" /> }}pinax/css/groups. padding: 5px.odd { background-color: #F3F3F3.even { background-color: #FAFAFA.10 Plugging the bookstore application into Pinax To to so.css" /> }}bookmarks/css/bookmarks. } table.css" /> }}pinax/css/tabs.css" /> }}pinax/css/topics.bookstore td h2 { margin: 0.css" /> }}pinax/css/wiki.pinaxtutorial Documentation.css" /> }}pinax/css/comments.html: {% block extra_head_base %} <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <link rel="stylesheet" href="{{ STATIC_URL <!-.bookstore td.

PROJECT_ROOT/bookstore/templates/bookstore/base.pinaxtutorial Documentation.. “Your books” and “Add a book”.end --> <li id="tab_swaps"><a href="{% url offer_list_all %}">{% trans "Swaps" %}</a></li> <li id="tab_locations"><a href="{% url loc_yours %}">{% trans "Locations" %}</a></li> <li id="tab_inbox"><a href="{% url messages_inbox %}">{% trans "Inbox" %} ({{ combined_in {% endspaceless %}</ul> {% endif %} {% endblock %} 3.11. This base template will be extend by all the Bookstore application templates.html template you have edited a while ago.here you insert the boookstore tab--> <li id="tab_bookstore"><a href="{% url all_books %}">{% trans "Bookstore" %}</a></li> <!-.html: {% extends "site_base. As you can easily deduct. {% block right_tabs %} {% if user.css" /> <!-.11. Release 0.. Now create a base template for the Bookstore application.7..end --> {% block extra_head %}{% endblock %} {% endblock %} . Writing the templates 29 .is_authenticated %} <ul class="tabs">{% spaceless %} <li id="tab_profile"><a href="{% url profile_detail user %}">{% trans "Profile" %}</a></l <li id="tab_photos"><a href="{% url photos %}">{% trans "Photos" %}</a></li> <li id="tab_blogs"><a href="{% url blog_list_all %}">{% trans "Blogs" %}</a></li> <li id="tab_tribes"><a href="{% url tribe_list %}">{% trans "Tribes" %}</a></li> <li id="tab_tweets"><a href="{% url tweets_you_follow %}">{% trans "Tweets" %}</a></li> <li id="tab_bookmarks"><a href="{% url all_bookmarks %}">{% trans "Bookmarks" %}</a></li> <!-.html" %} {% load i18n %} {% block rtab_id %}id="bookstore_tab"{% endblock %} {% block subnav %} <ul> <li><a href="{% url all_books %}">{% trans "All books" %}</a></li> <li><a href="{% url your_books %}">{% trans "Your books" %}</a></li> <li><a href="{% url add_book %}">{% trans "Add a book" %}</a></li> </ul> {% endblock %} Note that this base template extends the site_base.1 Writing the base template First create a PROJECT_ROOT/bookstore/templates/bookstore directory where you will place the templates needed by the Bookstore application.1 <link rel="stylesheet" href="{{ STATIC_URL }}bookstore/css/bookstore. the Bookstore application will have 3 sub menus: “All books”. 3.11 Writing the templates 3.

meta --> <td class="meta" > <div class="details">{% blocktrans %}added by{% endblocktrans %} <a href="{% {% blocktrans %}on{% endblocktrans %} {{ book.username }}"><i>{% blocktrans %} </td> <!-.adder. Release 0.publisher }}<br />{{ book.author }}<br /></strong></i> {{ book.description|linebreaks|truncatewords:50 }} </div> {% ifequal list ’yours’ %} <table> <tr> <td> <!-. Now it is time to create the books.book info --> <td> <h3><a href="/bookstore/{{ book. Before writing any template.html. the template for listing the books: PROJECT_ROOT/bookstore/templates/bookstore/books.11.2 Creating a template for listing the books This is the template that the application will use to render the books.1 3.id }}/book/">{{ book.alternate --> {% if books %} <table class="bookstore"> {% for book in books %} <tr class="{% cycle odd.title }}</a></h2> <div class="body"> <strong><i>{{ book. according to the way the get_thumb_url method is written (you could make things easily customisable with a variable in settings.pinaxtutorial Documentation. Developing the basic application and plugging it in Pinax . Also you need to create a PROJECT_ROOT/site_media/media/bookstore/thumb_100_100 directory to manage thumbnails. you need to create the directory that will actually contain them: create a bookstore directory in the templates directory of the project.7.py).added|date }} <a href="/bookstore/user_books/{{ book.html" %} {% load i18n %} {% block head_title %}{% blocktrans %}Bookstore{% endblocktrans %}{% endblock %} {% block body %} <h1> {% ifequal list ’all’ %} {% trans "All Books" %} {% endifequal %} {% ifequal list ’user’ %} {{ username }} {% trans "books" %} {% endifequal %} {% ifequal list ’yours’ %} {% trans "Your Books" %} {% endifequal %} </h1> <!-.even %}"> <!-. your_books and user_books views.id %}"> 30 Chapter 3.html template {% extends "bookstore/base.udpate book --> <form method="GET" action="{% url update_book book.

11. Create the book. “Your books”.cover art --> <td> <div class="coverart" >{{ book.11.” message 3. Writing the templates 31 .html template {% extends "bookstore/base.html template using the following code: PROJECT_ROOT/bookstore/templates/bookstore/book.pinaxtutorial Documentation.delete book --> <form method="POST" action="{% url delete_book book.html" %} {% load i18n %} {% load uni_form %} 3. Release 0. the publisher. a link for updating/deleting that book is displayed • if the books collection is empty the table is not created an the user is warned with a “No books yet.7.thumb|safe }}</div> </td> </tr> {% endfor %} </table> {% else %} <p>{% trans "No books yet. book info and coverart • the meta section displays the user that added the book (with a link to her/his profile). the author and the description (truncated after 50 characters).id %}"> <input type="submit" value="{% trans "Delete Book" %}" /> </form> </td> </tr> </table> {% endifequal %} </td> <!-. “An user books”) • the ‘books’ collection is iterated to create a table with a row for each book (the collection may be related to the whole book set. the date when the book has been added and a link to the full book list added by that user • the book info section displays the book’s title with a link to its page. to your book set or to a user book set • each row contains the following sections (one for each column): meta." %}</p> {% endif %} {% endblock %} Notes about this template: • the ‘list’ variable is used to define the title of the page (“All books”.3 Creating a template for viewing a book This is maybe the easiest of the templates you need to create. If the template is rendering the your_books view (thus if ‘list’ == ‘Your books’).1 <input type="submit" value="{% trans "Update Book" %}" /> </form> </td> <td> <!-.

publisher }}<br />{{ book.id %}"> <input type="submit" value="{% trans "Update Book" %}" /> </form> </td> <td> <!-.1 {% block head_title %}{% blocktrans %}Book Description{% endblocktrans %}{% endblock %} {% block body %} <h1>{{ book. author and description • book action displays the buttons to update or delete the book if the user is the one who has added it in the system • meta displays the user that added the book (with a link to his/her profile) and the date when the book has been added 32 Chapter 3.7.book info --> <h3>{{ book. Developing the basic application and plugging it in Pinax .html template.description|linebreaks }} </div> </p> <p> <!-. but here Django is rendering only one book. publisher. meta • book info displays the book’s cover art. You may note that: • the variable book is used to gain information about the book to render • the variable isyours is needed to let the user to update or delete the book if she/he is the user who has added it • there are 3 sections in the book representation: book info.id %}"> <input type="submit" value="{% trans "Delete Book" %}" /> </form> </td> </tr> </table> {% endif %} </p> <p class="meta"> <!-.meta --> <div class="details">{% blocktrans %}added by{% endblocktrans %} <a href="{% url profile_ </p> {% endblock %} It is a bit like the books.pinaxtutorial Documentation.title }}</h2> <div class="body"> <strong><i>{{ book. book action.book action --> {% if isyours %} <table> <tr> <td> <!-.udpate book --> <form method="GET" action="{% url update_book book.title }}</h1> <p> <div class="coverart" >{{ book. Release 0.author }}<br /></strong></i> {{ book.delete book --> <form method="POST" action="{% url delete_book book.fullpicture|safe }}</div> </p> <p> <!-. title.

html" %} {% load i18n %} {% load uni_form %} {% block head_title %}{% blocktrans %}Add Book{% endblocktrans %}{% endblock %} {% block body %} <h1>{% trans "Add Book" %}</h1> <form enctype="multipart/form-data" method="POST" action="" class="uniForm"> <fieldset class="inlineLabels"> {{ book_form|as_uni_form }} <div class="form_block"> <input type="submit" value="{% trans ’add book’ %}"> </div> </fieldset> </form> {% endblock %} Here there is nothing much to explain. Writing the templates 33 .html template.7.the book . 3.11.title }}</h1> <form enctype="multipart/form-data" method="POST" action="" class="uniForm"> <p align=’center’>{{ book. you are rendering the template with a BookForm variable.coming from the view.html template {% extends "bookstore/base.4 Creating a template for adding a book Now create the add.11.html ones.fullpicture|safe }}</p> <fieldset class="inlineLabels"> {{ book_form|as_uni_form }} <div class="form_block"> <input type="submit" value="{% trans ’update book’ %}"> </div> </fieldset> </form> {% endblock %} Basically this template is like the add.html template {% extends "bookstore/base. for updating a book in the bookstore: PROJECT_ROOT/bookstore/templates/bookstore/update.1 3. for adding new books to the bookstore: PROJECT_ROOT/bookstore/templates/bookstore/add.html" %} {% load i18n %} {% load uni_form %} {% block head_title %}{% blocktrans %}Add Book{% endblocktrans %}{% endblock %} {% block body %} <h1>{% trans "Update Book: " %}{{ book.pinaxtutorial Documentation. with another variable .5 Creating a template for updating an existing book Time to create the update template.11. 3. Release 0.

Visit the Bookstore all books page: http://localhost:8000/bookstore/ 34 Chapter 3. start the development server and try visiting the pages and access the features you have implemented. Visit the Pinax home page: http://localhost:8000 1. you may finally test if everything is working properly. 1. If you still didn’t do so. the view and the templates of the application. Developing the basic application and plugging it in Pinax .pinaxtutorial Documentation.7.1 3.12 A quick tour of the basic bookstore application Now that you are over writing the models. Release 0.

Consult your books: http://localhost:8000/bookstore/your_books/ 1. A quick tour of the basic bookstore application 35 .7.pinaxtutorial Documentation.1 1. Release 0.12. Consult the books added by a different users: http://localhost:8000/bookstore/user_books/admin/ 3.

Add a book: http://localhost:8000/bookstore/add/ 1.1 1.pinaxtutorial Documentation. View a book: http://localhost:8000/bookstore/4/book/ 36 Chapter 3. Developing the basic application and plugging it in Pinax .7. Release 0.

12.pinaxtutorial Documentation.1 1.7. Update a book added by you: http://localhost:8000/bookstore/4/update/ 3. Release 0. A quick tour of the basic bookstore application 37 .

you may read the next tutorial parts (as soon as they will appear at this blog) in order to implement other features like localization. 3. and flags for contents.com/capooti/pinaxtutorial Code for this part is here: http://github. comments. profiles. and the tutorial text in restructured text format (Sphinx ready). notifications. pagination. voting.pinaxtutorial Documentation. Release 0.7. Developing the basic application and plugging it in Pinax .14 Where can I get the code? The whole tutorial is at gitHub: http://github. avatars. Basically. you may be able to follow each of these parts without proceding in the tutorial’s order.1 3. tagging.13 What’s next Now that you are ready with the basic bookstore application. 38 Chapter 3. feeds.com/capooti/pinaxtutorial/commits/PinaxTutorial-2 There you can download tutorial’s code.

If you are reading the pdf version of the tutorial or the reST documentation.utils. then this documentation is already updated with the templates directory in the right place). For example: In the model: PROJECT_ROOT/bookstore/models.utils.1 Using translation strings in Python code and templates In the Bookstore application we have already used translation strings in Python code and templates with the help of the django. if you completed the other parts of this tutorial before the date of this post.ugettext_lazy() function and the {% trans %} (and {% blocktrans %}) template tag. adder. added """ title = models. max_length=255) 39 . In this part of the tutorial I will show how easy it is to enable your application for internationalization with Pinax. 4. you need to move the PROJECT_ROOT/templates/bookstore directory in PROJECT_ROOT/bookstore/templates: so now you will have a PROJECT_ROOT/bookstore/templates/bookstore directory. You can find a complete discussion about Django’s internationalization mechanism here Be sure to read this discussion before going on with this tutorial. publisher. max_length=255) publisher = models.translation import ugettext_lazy as _ class Book(models.CharField(_(’publisher’). coverart. and doing so I am following the Django best practices. I did so for a better deployment experience.translation. from django.Model): """ Book Model: title. author. Enabling internationalization for a Pinax application is just the same procedure for enabling it for a Django application. To enable internationalization for your application you will need to complete three steps: • use translation strings in Python code and templates • create language files • change settings Let’s see how to apply them to the Bookstore application you are developing.. description.CharField(_(’title’).CHAPTER FOUR INTERNATIONALIZATION OF THE APPLICATION (Note that.py: ..

.views...pinaxtutorial Documentation.1 Language files for the Bookstore application For example create a message file for Italian language by using the django-admin.save() request. as suggested at the ending).. Release 0.py makemessages tool.create(message=_("You have saved book ’%(title)s’") % return HttpResponseRedirect(reverse("bookstore. from django. max_length=255) ..py: ..save(commit=False) new_book.7. 4.CharField(_(’author’).user new_book.FILES) if book_form. Internationalization of the application . In the views: PROJECT_ROOT/bookstore/views..translation import ugettext_lazy as _ . """ # POST request if request.html: {% extends "site_base.. so if you have time try to cover the totality of the code (or download the source code of this tutorial part at gitHub.user.. {’tit In the templates: PROJECT_ROOT/bookstore/templates/bookstore/base. First we are going to create the message file in the application directory to enable internationalization for the Bookstore Application (note that we need to create a locale directory before): 40 Chapter 4. @login_required def add_book(request): """ Add a book to the bookstore..2 Creating and compiling language files Once you have tagged your strings for being translated.message_set..is_valid(): new_book = book_form.books")) . request..adder = request.1 author = models.POST.method == "POST": book_form = BookForm(request.utils.html" %} {% load i18n %} {% block rtab_id %}id="bookstore_tab"{% endblock %} {% block subnav %} <ul> <li><a href="{% url all_books %}">{% trans "All books" %}</a></li> <li><a href="{% url your_books %}">{% trans "Your books" %}</a></li> <li><a href="{% url add_book %}">{% trans "Add a book" %}</a></li> </ul> {% endblock %} Note that I did not use translation strings for everything in the previous chapters. 4.2. you need to write the languages files for any language you wish the application needs to be translated.

Release 0.py:25 msgid "There is already this book in the library..html:61 msgid "Bookstore" msgstr "Libreria" #: templates/site_base.2.py makemessages -l i processing language it Edit the msgstr for each msgid also for this file: PROJECT_ROOT/locale/it/LC_MESSAGES/django." msgstr "Esiste già questo libro nella libreria. and change the msgstr for each msgid.2.py makemes processing language it Open the django.po: .py:17 msgid "publisher" msgstr "editore" .. 4.2 Language files for the Pinax project If you didn’t get Pinax packaged with the message files of the language you wish.1 (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial/bookstore$ django-admin.py makemes Error: This script should be run from the Django SVN tree or your project or app tree. To do so. If you did ind (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial/bookstore$ mkdir locale (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial/bookstore$ django-admin..html:59 msgid "Bookmarks" msgstr "Segnalibri" #: templates/site_base.pinaxtutorial Documentation.html:64 msgid "Locations" msgstr "Località" 4.py:16 msgid "title" msgstr "titolo" #: models. you may need to repeat the same procedure at a project level.po: #: templates/site_base. create the message file in the project directory to enable internationalization for this Pinax Project: (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial$ mkdir locale (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial$ django-admin.po file that has been created.. #: forms.html:63 msgid "Swaps" msgstr "Scambi" #: templates/site_base." #: models.7. Creating and compiling language files 41 . PROJECT_ROOT/bookstore/locale/it/LC_MESSAGES/django.

2. open the settings. The application should be now available also in Italian (or whatever language you may have decided to translate): 42 Chapter 4. Internationalization of the application . you will realize that your translations are still not there.py file and make sure you have the following settings: . ) Now you can try your project (change the Pinax language by using the dropdown list in the upper right)..py compile processing file django.po files by using the django-admin.. ugettext = lambda s: s LANGUAGES = ( (’en’. # If you set this to False.py tool with the compilemessages option: (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial/bookstore$ django-admin.py compilemessages processing file django. u’Italiano’). so do it now..7. (’it’.1 4.3 Compiling the language files Now you need to compile the messages you modified in both the django. Release 0. This is because the bookstore application has now the Italian translation. Remember to restart the development server every time you compile the messages.3 Changing settings If now you try the Bookstore application. but you need to make Django aware of the languages supported by the application. To do so.po in /home/paolo/virtualenv/pinax-env/pinaxtutorial/locale/it/LC_MESSAGES If you examinate both the LC_MESSAGES directory you should find a binary file named django. u’English’).mo.po in /home/paolo/git/pinaxtutorial/bookstore/locale/it/LC_MESSAGES (pinax-env)paolo@paolo-laptop:~/virtualenv/pinax-env/pinaxtutorial$ django-admin.. Django will make some optimizations so as not # to load the internationalization machinery. 4. USE_I18N = True .pinaxtutorial Documentation.

1 4.4. Release 0.7.pinaxtutorial Documentation.4 Notes As usual I have updated the gitHub repository for this project (the tutorial) with all the stuff you many need to go along with it: • You can find the code of this part of the tutorial here • You can find updated documentation in reST format here • You can download a pdf copy of this tutorial here http://github. Notes 43 .pdf 4.com/capooti/pinaxtutorial/blob/PinaxTutorial3/pinaxtutorial.

7.pinaxtutorial Documentation. Release 0.1 44 Chapter 4. Internationalization of the application .

book. For managing avatars in the Pinax application you are building.html template 45 .html): PROJECT_ROOT/bookstore/templates/bookstore/books. the default for this is true so you shouldn’t do anything there). you will use the Avatar application (be sure you are importing it in your settings file.CHAPTER FIVE USING AVATARS. and the second parameter is the avatar size in pixels.html.adder 40 %} Where the first parameter is the user for which you want to render the avatar.2 Adding support for avatars In Pinax you may use two kind of avatars for your users (in both case you may manage them from the Avatar page: http://localhost:8000/avatar/change/): • gravatars • custom avatars In the first case Pinax will render your avatar using the gravatar you have associated to your email from the Gravatar web service. PAGINATION AND PROFILES 5.0 sites is supposed to offer: • support for avatars • support for pagination • support for user profiles 5. Adding support for avatars in your Pinax application is just as easy as to do the following two things in your templates: • import the avatar tags library {% load avatar_tags %} • use the {% avatar %} tag in your templates For the Bookstore application it will be enough to use the avatar tag in this way: {% avatar book. So you need to do this in your templates (books. In the latter Pinax will use a custom avatar you have uploaded to the Pinax web site.1 Introduction In this part we will improve the Bookstore application and we will see how easy it is to add support for three core features that any web 2.

adder 40 %}</div> <div class="details">{% blocktrans %}added by{% endblocktrans %} <a href="{% url prof </p> . 46 Chapter 5.meta --> <td class="meta" > <div class="avatar" >{% avatar book. the default for this is true so you shouldn’t do anything there).adder 40 %}</div> <div class="details">{% blocktrans %}added by{% endblocktrans %} <a href= .pinaxtutorial Documentation. Using avatars.html" %} {% load i18n %} {% load avatar_tags %} . you will use the Pagination application (be sure you are importing it in your settings file. pagination and profiles . Release 0.7.1 {% extends "bookstore/base.alternate --> {% if books %} <table class="bookstore"> {% for book in books %} <tr class="{% cycle odd... <!-.meta --> <div class="avatar" >{% avatar book. Now if you run your application.html template {% load i18n %} {% load uni_form %} {% load avatar_tags %} .. PROJECT_ROOT/bookstore/templates/bookstore/book. you will see that avatars are there: http://localhost:8000/bookstore/ 5..3 Adding support for pagination For managing pagination in the Pinax application you are building... <p class="meta"> <!-..even %}"> <!-..

you will see that the support for pagination is now implemented: http://localhost:8000/bookstore/ 5.html template {% extends "bookstore/base..pinaxtutorial Documentation.html template: PROJECT_ROOT/bookstore/templates/bookstore/books..7.1 Adding support for pagination in your Pinax application is just as easy as to do the following two things in your templates: • import the pagination tags library {% load pagination_tags %} • use the {% autopaginate %} and {% paginate %} tag in your templates For the Bookstore application it will be enough to use the autopaginate tag in this way: {% autopaginate books 5 %} Where the first parameter is the collection for which you want to implement pagination.. Adding support for pagination 47 . Now if you run your application. {% endfor %} </table> {% paginate %} . So you need to do this in your books. Release 0.. and the second parameter is the number of elements for each page (5 books for each pagination)..html" %} {% load i18n %} {% load avatar_tags %} {% load pagination_tags %} . {% if books %} {% autopaginate books 5 %} <table class="bookstore"> {% for book in books %} .3..

Release 0.all. As you many notice.html template and I add a Books section in it. the photoes and so on: basically all the contents that have been added by that user. Using avatars. instead I will copy this template in the the Pinax project and will modify it..1 5.7. the bookmarks. like in the following code: PROJECT_ROOT/templates/profiles/profile. the blog posts. <h2>{% trans "Bookmarks" %}</h2> . Now run your application and note that if you access an user profile page.select_rela <tr class="{% cycle odd.. you will realize that you need to customize this template: PINAX_ROOT/templates/default/profiles/profile.4 Adding support for user profiles Pinax provide a Profile page: a page where it is possible to get information about a particular user. <h2>{% trans "Books" %}</h2> {% if other_user... the tweets. You may see how it is structured this page reaching this url: http://localhost:8000/profiles/profile/username/ (replace username with the username for which you want to see the Profile page).html: .des </td> <td> <div class="coverart" >{{ boo </td> </tr> {% endfor %} </table> {% else %} {% url add_bookmark as add_bookmark_url %} <p>{% blocktrans %}You haven’t added any <a href="/bookstore/ {% endif %} <h2>{% trans "Blog Posts" %}</h2> . So I copy this template as PROJECT_ROOT/templates/profiles/profile. for example for each user our project (based on the Pinax social project) presents you: the wiki articles.added_books.pinaxtutorial Documentation..added|date }} </td> <td> <h2><a href="/bookstore/{{ bo <div class="body">{{ book.added_books. For doing so if you investigate in the Pinax source code. pagination and profiles . there are many things in the Profile page..html But I do not want to modify Pinax source code. We want to add in the Profile page a section for the Bookstore: there will be the books that have been added in the Bookstore application by that user.all %} <table class="bookstore narrow"> {% for book in other_user. you will also see the books he/she has added to the Bookstore application in the portal: 48 Chapter 5.even %}"> <td class="meta"> {{ book.

com/capooti/pinaxtutorial/tree/PinaxTutorial4/docs/>‘_ • You can download a pdf copy of this tutorial here http://github.pdf 5.5.pinaxtutorial Documentation.5 Notes As usual I have updated the gitHub repository for this project (the tutorial) with all the stuff you many need to go along with it: • You can find the code of this part of the tutorial here • You can find updated documentation in reST format ‘ here <http://github.com/capooti/pinaxtutorial/blob/PinaxTutorial4/pinaxtutorial.7. Release 0.1 5. Notes 49 .

1 50 Chapter 5.pinaxtutorial Documentation. pagination and profiles .7. Release 0. Using avatars.

. 51 . but these are the most common): • Django comments framework • the django-threadedcomments system. . you could add this feature by using one of these two approaches (there may be other ones. that . 6. ) if you didn’t customize things. in your settings file. ’bookstore’.2 Setup You need to make sure that. Basically.as suggested by its name .1 Introduction In this part we will improve the Bookstore application: what I am going to show is how easy it is to add support for enabling comments for a book without writing from scratch another comment system (as you may already now.py: INSTALLED_APPS = ( .3 Using django-threadedcomments in the templates Now that you have enabled in your project the django-threadedcomments system. ’threadedcomments_extras’.. ’threadedcomments’. it is very easy to add support for comments in your pages (templates).it offers support for comments in a threaded fashion You will implement a commenting system in the application you are developing by using the djangothreadedcomments system. avoid rewriting things is the core philosophy of Pinax and Django)... you have the django-threadedcomments system enabled: PROJECT_ROOT/settings.CHAPTER SIX ADDING A COMMENT SYSTEM 6. 6. you should have this two applications already enabled (not commented).

html" %} {% load i18n %} {% load uni_form %} {% load avatar_tags %} {% load comments_tag %} . to display the number of comments for each book. <!-..3.comments --> <h3 id="comments">{% blocktrans %}Comments on this Book{% endblocktrans %}:</h3> {% comments book %} .. Release 0. Now if you navigate to a book page.. To do so you need to do basically two things: • Add {% load comments_tag %} • Insert the {% comments %} tag where is needed (where you want to enable comments) This is how it should look the code of the PROJECT_ROOT/bookstore/templates/bookstore/book.pinaxtutorial Documentation.7. in the books..1 Modifying the book.3. You need to modify the book.2 Modifying the books.html template. it will be possible to add new comment or reply to existing comments: 6.html template.meta --> . Adding a comment system .html template First we want to make possible to add comments for a book.1 6..html template {% extends "bookstore/base.html template We also want. <p class="meta"> <!-. To do so do the following: • Add {% load threadedcommentstags %} • use the get_comment_count function as needed 52 Chapter 6..

How it works 53 . ..4 How it works Note that you didn’t sync the database because the table needed from the django-threadedcomments’s model (named threadedcomments_threadedcomment) was already created when you first have created the project. <table class="bookstore"> {% for book in books %} ....1 PROJECT_ROOT/bookstore/templates/bookstore/books.pinaxtutorial Documentation.author }}<br /></strong></i> {{ book. 6..publisher }}<br />{{ book.png" border="0" class="noborder" al <a href="/bookstore/{{ book.... {% endfor %} If you navigate to the books page. Release 0. it will be possible to see how many comments have been posted for each book: 6. <div class="body"> <strong><i>{{ book. If you access to the contents of this table.4.html" %} {% load i18n %} {% load avatar_tags %} {% load pagination_tags %} {% load threadedcommentstags %} .7.id }}/book/#comments">{% get_comment_count for book as co {{ commentcount }} Comments</a><br /> {% ifequal list ’yours’ %} . for example via the admin: http://localhost:8000/admin/threadedcomments/threadedcomment/ you can notice that a row is created for every comment that has been inserted in the portal.description|linebreaks|truncatewords:50 }} </div> <!-.html template {% extends "bookstore/base.comments --> <img src="{{ STATIC_URL }}pinax/images/silk/icons/comment.

7. Adding a comment system . Release 0.5 Notes As usual I have updated the gitHub repository for this project (the Pinax Tutorial) with all the stuff you many need to go along with it: • You can find the code of this part of the tutorial here • You can find updated documentation in reST format ‘ here <http://github. 6.com/capooti/pinaxtutorial/blob/PinaxTutorial5/pinaxtutorial.pinaxtutorial Documentation.1 Important fields of this table are: • user_id: the user that created the comment • content_type: the content type for which the comment has been created (in this case a book) • object_id: the content for which the comment has been created • parent_id: a self join to the comment for which the comment is threaded (null if it is not threaded) by storing this information in the database. it is easy to relate a comment to a specific book (or to other contents in the portal).com/capooti/pinaxtutorial/tree/PinaxTutorial5/docs/>‘_ • You can download a pdf copy of this tutorial here http://github.pdf 54 Chapter 6.

CHAPTER SEVEN INDICES AND TABLES • Index • Module Index • Search Page 55 .

Sign up to vote on this title
UsefulNot useful