Sep 18

Getting started with Pinax

NOTE: This content is a little out of date. Some of the layout might be wrong, but the ideas are still relavent.

I went ahead today and figured that I would try out Pinax, seeing as it's been getting a lot of good press in the Django community lately. The talk from James Tauber at Djangocon was really good, and I certainly recommend checking it out. This is going to be a basic introduction to pinax.

First thing you need to do is grab the code from the pinax repository.

svn checkout http://svn.pinaxproject.com/pinax/trunk/ pinax

Once you have the code checked out you are already half of the way there. The only current external dependency is on PIL, the Python Imaging Library. Django itself has this dependency for the ImageField in forms. More than likely you already have this installed, so it shouldn't be a problem. If not, that is the only dependency of Pinax.

The directory structure of Pinax is pretty simple, copying from the README:

pinax/          contains a django project and templates
external_apps/  contains external re-usable apps brought in via svn:externals
local_apps/     contains re-usable apps that aren't yet externalized
core_apps/      contains non re-usable apps specific to pinax site
external_libs/  contains external libraries

The manage.py script inside of pinax links up all of the apps correctly for you. So all you need to do to get started is go into pinax/ and run ./manage.py syncdb. Then go ahead and run ./manage.py runserver and you should see the pinax welcome page! That is pretty awesomely simple to get up and running!

At this point, you now basically have an entire social application working on your box. That is pretty damn impressive. The pinax directory is the project directory in this setup. Then, all you have to do is swap out the templates, and you have your own site with the exact same functionality.

The main use case for me with Pinax is to take the groundwork that they're layed and throw a little bit of custom code on top. That is the goal of the project. They are trying to give you a really solid base that provides all of the generic functionality that 99% of websites need. From this base it is then incredibly easy and fast to get "yet another X site" going, wherein you then add the magic that makes your site unique.

A couple days ago I actually took my first Django site I'd ever done and converted it over to Pinax. It took all of about two hours, with the awesome help of James Tauber and Brian Rosner in the #pinax IRC channel on Freenode. They were helpful and I bemoaned the lack of documentation, so that's why I'm writing this up :) The site is now about 100x more powerful, and it's really cool the power of Pinax there.

I want to talk about my philosophy behind the usage of Pinax. The way that I've been thinking about it is basically it gives you the groundwork with some nice default templates for the apps. The way that you go about skinning the app is with the base.html and site_base.html in the pinax/templates/ directory. base.html allows you to change the basic layout of the site. This is where I changed out my CSS and Javscript code. Basically you don't want to be changing any of the block tags here, just HTML. I ripped everything out of the except for </code> and <code>{% block extra_head %}</code>. In the <code><body></code> I basically ripped everything out, and put in my previous template, then adjusted the block tags to make them appropriate. </p> <p>One of the big gotcha's is the way that template blocks are named. The pinax app templates are all coded to specific block names (as they have to be), but if you're trying to use existing templates then you might need to update your blocks if you want to be able to have the backend stuff "just work". Here is a listing of the main template block names and what they are. Remember, these simply need to be present in your <code>base.html</code>, and they will be given content in <code>site_base.html</code>.</p> <p>{%block logo_link_image %} This is where your image goes (in the header) {% block login %} Is where the login stuff goes (leave this empty if you want to use their auth) {% block tabs %} Menu or tabs, since it's only used in base and site_base, this can really be anything. {% block body %} This is where your main content goes. {% block footer %} This is where you put the footer contents</p> <p>A couple more gotchas: </p> <ul> <li>The pinax manage.py does a decent amount of editing of your PYTHONPATH, so if you want to deploy it then you need to understand how this works. Check out <a href="http://www.20seven.org/journal/2008/09/pinax-setup-and-deploy.html">this post</a> by Greg Newman for help with deployment!</li> <li>The media in pinax is served out of <code>pinax/site_media</code> and in URLs are site_media, so you need to put all of your css and javascript in there to get it working on the dev server. When you deploy this can go back to where it was previously (assuming previous install).</li> <li>At the bottom of the pinax settings file, you see it does an import of localsettings. You can define your own settings than override the pinax ones in a localsettings.py file anywhere on the PYTHONPATH. This keeps you pretty safe from updating pinax and having it wipe your settings in the default settings file.</li> <li>Remember this is still a work in progress, so the code will be updated (and probably break backwards compatibility) pretty frequently. Keep an eye on the <a href="http://code.google.com/p/django-hotclub/wiki/BackwardsIncompatibleChanges">BackwardsIncompatibleChanges</a></li> </ul> <p>That's enough for today. That should get you up and running with Pinax. I will be doing a screencast on this stuff sometime this weekend, so look out for that. It should make this a lot more obvious.</p> </div> </div> <div class="subscribe clearfix"> <a href="http://twitter.com/?status=reading: Getting started with Pinax - http://ericholscher.com/blog/2008/sep/18/getting-started-pinax/" target="_blank">Twitter this</a> | <a href="http://www.reddit.com/submit?title=Getting started with Pinax&url=http://ericholscher.com/blog/2008/sep/18/getting-started-pinax/" target="_blank">Reddit this</a> | <a href="http://delicious.com/save" onclick="window.open('http://delicious.com/save?v=5&noui&jump=close&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title), 'delicious','toolbar=no,width=550,height=550'); return false;">Add to Delicious</a> | <a href="http://feeds.feedburner.com/EricsThoughts">Subscribe RSS</a> </div> <!-- post --> <hr> <div id="comments"> <a name="comments"></a> <h3 class="comments_title">Comments</h3> <div class="comment"> <h5 class="name"> <a name="c52" href="/comments/cr/17/94/#c52" title="Permalink to 's comment" class="count">1</a> <a rel="nofollow external" href="http://www.red4.bz/">Israel</a> says... </h5> <p>Thanks Eric,</p> <p>I'm about to deploy a site on pinax and this helps a lot!</p> <p class="date">Posted at 4:08 p.m. on September 19, 2008</p> </div> <div class="comment"> <h5 class="name"> <a name="c56" href="/comments/cr/17/94/#c56" title="Permalink to 's comment" class="count">2</a> wcyee says... </h5> <p>Nice post, thanks. In case you're gathering votes, here's my +1 for changing the foreground/background scheme you have going. :-)</p> <p class="date">Posted at 1:04 p.m. on September 23, 2008</p> </div> <div class="comment"> <h5 class="name"> <a name="c96" href="/comments/cr/17/94/#c96" title="Permalink to 's comment" class="count">3</a> <a rel="nofollow external" href="http://www.varud.com/">Adam Nelson</a> says... </h5> <p>With the latest and greatest pinax, syncdb needs to be done from ./projects/complete_project as the directory structure appears to have changed. Also, on Debian, run: sudo apt-get python-imaging to get the imaging library. In theory, it would work without the imaging library but in reality it doesn't.</p> <p class="date">Posted at 6:28 p.m. on October 9, 2008</p> </div> <div class="comment"> <h5 class="name"> <a name="c101" href="/comments/cr/17/94/#c101" title="Permalink to 's comment" class="count">4</a> <a rel="nofollow external" href="http://code.google.com/p/a-django-hotclub-theme/">matagus</a> says... </h5> <p>Great article! I'm doing some basic css themes for pinax. By now I've only modified base.css file to change colors, tipography and borders. If you are interested please visit google code project page: <a href="http://code.google.com/p/a-django-hotclub-theme/" rel="nofollow">http://code.google.com/p/a-django-hotclub-theme/</a></p> <p class="date">Posted at 3:13 a.m. on October 13, 2008</p> </div> <div class="comment"> <h5 class="name"> <a name="c747" href="/comments/cr/17/94/#c747" title="Permalink to 's comment" class="count">5</a> <a rel="nofollow external" href="http://worldfrenzy.com/">Olen</a> says... </h5> <p>One function, which I feel is important, seems to be lacking in the demo site: A search of the profiles. This is a major function at networks like facebook, etc. There were 178 pages of members and members "handles" are for the most part meaningless. Is there the ability to search for a member by name or location, etc? I can see why it might be left out of the demo. But, for a fully functional site, omitting this ability would really cripple members abilities to connect to friends, etc.</p> <p class="date">Posted at 2:55 a.m. on January 14, 2009</p> </div> </div> <h4>Comment are disabled for this post.</h4> </div><!-- end .grid_8 --> <div class="grid_4 sidebar"> <h4> About this post </h4> <p>Posted at 9:52 p.m. on September 18, 2008</p> <p>Comments: <a href="#comments">5</a></p> <p>Tags: <a rel="tag" href="/tag/django/">django</a> , <a rel="tag" href="/tag/pinax/">pinax</a> , <a rel="tag" href="/tag/tips/">tips</a> </p> <div class="related"> <h4>Related</h4> <p> <a href="/blog/2011/jan/10/handling-django-settings-files/">Handling Django Settings Files</a><br> <a href="/blog/2009/nov/18/finding-missing-indexes-django-wants/">Finding Missing Indexes That Django Wants (Postgres)</a><br> <a href="/blog/2008/nov/8/problem-django-template-tags/">The problem with Django's Template Tags</a><br> </p> </div> <form action="/search/" method="GET" id="post_search_form"> <p> <input type="text" name="q" value="" id="searchbox" /> </p> </form> <h4>About</h4> <p>Welcome to the home of Eric Holscher on the web. I talk about software development, mostly in the realm of Django. I am interested in the real time web, testing, mobile apps, and other things. </p> <h4>Projects</h4> <ul> <li> <a href="http://readthedocs.org">Read The Docs</a> </li> <li> <a href="http://devmason.com">DevMason</a> </li> <li> <a href="http://pypants.org">PyPants</a> </li> <li> <a href="http://django-test-utils.readthedocs.org/">Django Test Utils</a> </li> <li> <a href="http://django-kong.readthedocs.org/">Django Kong</a> </li> </ul> <h4>Recent Posts</h4> <p><a href="/blog/2012/jan/22/why-read-docs-matters/" title="Why Read the Docs matters ">Why Read the Docs matters </a><br> 1 week, 5 days ago (Comments: <a href="/blog/2012/jan/22/why-read-docs-matters/#comments">7</a>)</p> <p><a href="/blog/2011/apr/11/read-docs-update/" title="Read the Docs Update ">Read the Docs Update </a><br> 9 months, 4 weeks ago (Comments: <a href="/blog/2011/apr/11/read-docs-update/#comments">2</a>)</p> <p><a href="/blog/2011/jan/24/using-reviewboard-git/" title="Using Reviewboard with Git">Using Reviewboard with Git</a><br> 1 year ago (Comments: <a href="/blog/2011/jan/24/using-reviewboard-git/#comments">0</a>)</p> <p><a href="/blog/2011/jan/11/read-docs-updates/" title="Read the Docs Updates">Read the Docs Updates</a><br> 1 year ago (Comments: <a href="/blog/2011/jan/11/read-docs-updates/#comments">1</a>)</p> <p><a href="/blog/2011/jan/10/handling-django-settings-files/" title="Handling Django Settings Files">Handling Django Settings Files</a><br> 1 year ago (Comments: <a href="/blog/2011/jan/10/handling-django-settings-files/#comments">12</a>)</p> <p><a href="/blog/2010/nov/17/required-reading/" title="Required Reading">Required Reading</a><br> 1 year, 2 months ago (Comments: <a href="/blog/2010/nov/17/required-reading/#comments">0</a>)</p> <p><a href="/blog/2010/nov/17/using-haystack-index-non-database-content/" title="Using Haystack to index non-database content">Using Haystack to index non-database content</a><br> 1 year, 2 months ago (Comments: <a href="/blog/2010/nov/17/using-haystack-index-non-database-content/#comments">4</a>)</p> <p><a href="/blog/2010/nov/15/correct-commands-check-out-and-update-vcs-repos/" title="Correct commands to check out and update VCS repos">Correct commands to check out and update VCS repos</a><br> 1 year, 2 months ago (Comments: <a href="/blog/2010/nov/15/correct-commands-check-out-and-update-vcs-repos/#comments">0</a>)</p> <p><a href="/blog/2010/nov/12/site-upgrades/" title="Site upgrades">Site upgrades</a><br> 1 year, 2 months ago (Comments: <a href="/blog/2010/nov/12/site-upgrades/#comments">0</a>)</p> <p><a href="/blog/2010/nov/11/building-django-app-server-chef-part-4/" title="Building a Django App Server with Chef: Part 4">Building a Django App Server with Chef: Part 4</a><br> 1 year, 2 months ago (Comments: <a href="/blog/2010/nov/11/building-django-app-server-chef-part-4/#comments">1</a>)</p> <h4>Popular Posts</h4> <p><a href="/blog/2010/nov/17/required-reading/" title="Required Reading">Required Reading</a></p> <p><a href="/blog/2011/jan/24/using-reviewboard-git/" title="Using Reviewboard with Git">Using Reviewboard with Git</a></p> <p><a href="/blog/2008/jul/8/setting-django-and-mod_wsgi/" title="Setting up Django and mod_wsgi">Setting up Django and mod_wsgi</a></p> <p><a href="/blog/2010/nov/8/building-django-app-server-chef/" title="Building a Django App Server with Chef: Part 1">Building a Django App Server with Chef: Part 1</a></p> <p><a href="/blog/2008/sep/12/screencast-django-command-extensions/" title="Screencast: Django Command Extensions">Screencast: Django Command Extensions</a></p> <p><a href="/blog/2008/oct/5/django-tips/" title="Big list of Django tips (and some python tips too) ">Big list of Django tips (and some python tips too) </a></p> <p><a href="/blog/2011/jan/10/handling-django-settings-files/" title="Handling Django Settings Files">Handling Django Settings Files</a></p> <p><a href="/blog/2010/aug/16/lessons-learned-dash-easy-django-deployment/" title="Lessons Learned From The Dash: Easy Django Deployment">Lessons Learned From The Dash: Easy Django Deployment</a></p> <p><a href="/blog/2010/jun/23/large-problems-django-mostly-solved-delayed-execut/" title="Large Problems in Django, Mostly Solved: Delayed Execution">Large Problems in Django, Mostly Solved: Delayed Execution</a></p> <p><a href="/blog/2010/nov/9/building-django-app-server-chef-part-2/" title="Building a Django App Server with Chef: Part 2">Building a Django App Server with Chef: Part 2</a></p> <h4>Friends</h4> <ul> <li> <a href="http://charlesleifer.com/">Charlie</a> </li> <li> <a href="http://codysoyland.com">Cody</a> </li> <li> <a href="http://drusellers.com/">Dru</a> </li> <li> <a href="http://frankwiles.com/">Frank</a> </li> <li> <a href="http://jacobian.org">Jacob</a> </li> <li> <a href="http://b-list.org">James</a> </li> <li> <a href="http://jannisleidel.com/">Jannis</a> </li> <li> <a href="http://playgroundblues.com">Nathan</a> </li> <li> <a href="http://traviscline.com">Travis</a> </li> </ul> <h4>Categories</h4> <ul> <li><a href="/blog/categories/links/" title="Links">Links</a></li> <li><a href="/blog/categories/personal/" title="Personal">Personal</a></li> <li><a href="/blog/categories/planet-django/" title="Planet Django">Planet Django</a></li> <li><a href="/blog/categories/python/" title="Python">Python</a></li> <li><a href="/blog/categories/school/" title="School">School</a></li> <li><a href="/blog/categories/screencasts/" title="Screencasts">Screencasts</a></li> <li><a href="/blog/categories/work/" title="Work">Work</a></li> </ul> <h4>Archive</h4> <ul class="archive"> <li><a href="/blog/2012/01/" title="January 2012">January 2012</a></li> <li><a href="/blog/2011/04/" title="April 2011">April 2011</a></li> <li><a href="/blog/2011/01/" title="January 2011">January 2011</a></li> <li><a href="/blog/2010/11/" title="November 2010">November 2010</a></li> <li><a href="/blog/2010/09/" title="September 2010">September 2010</a></li> <li><a href="/blog/2010/08/" title="August 2010">August 2010</a></li> <li><a href="/blog/2010/06/" title="June 2010">June 2010</a></li> <li><a href="/blog/2010/02/" title="February 2010">February 2010</a></li> <li><a href="/blog/2010/01/" title="January 2010">January 2010</a></li> <li><a href="/blog/2009/11/" title="November 2009">November 2009</a></li> <li><a href="/blog/2009/10/" title="October 2009">October 2009</a></li> <li><a href="/blog/2009/09/" title="September 2009">September 2009</a></li> <li><a href="/blog/2009/06/" title="June 2009">June 2009</a></li> <li><a href="/blog/2009/05/" title="May 2009">May 2009</a></li> <li><a href="/blog/2009/04/" title="April 2009">April 2009</a></li> <li><a href="/blog/2009/03/" title="March 2009">March 2009</a></li> <li><a href="/blog/2009/02/" title="February 2009">February 2009</a></li> <li><a href="/blog/2009/01/" title="January 2009">January 2009</a></li> <li><a href="/blog/2008/12/" title="December 2008">December 2008</a></li> <li><a href="/blog/2008/11/" title="November 2008">November 2008</a></li> <li><a href="/blog/2008/10/" title="October 2008">October 2008</a></li> <li><a href="/blog/2008/09/" title="September 2008">September 2008</a></li> <li><a href="/blog/2008/08/" title="August 2008">August 2008</a></li> <li><a href="/blog/2008/07/" title="July 2008">July 2008</a></li> <li><a href="/blog/2008/06/" title="June 2008">June 2008</a></li> <li><a href="/blog/2008/05/" title="May 2008">May 2008</a></li> <li><a href="/blog/2008/04/" title="April 2008">April 2008</a></li> <li><a href="/blog/2008/03/" title="March 2008">March 2008</a></li> <li><a href="/blog/2008/02/" title="February 2008">February 2008</a></li> <li><a href="/blog/2008/01/" title="January 2008">January 2008</a></li> <li><a href="/blog/2007/12/" title="December 2007">December 2007</a></li> <li><a href="/blog/2007/11/" title="November 2007">November 2007</a></li> <li><a href="/blog/2007/10/" title="October 2007">October 2007</a></li> <li><a href="/blog/2007/03/" title="March 2007">March 2007</a></li> <li><a href="/blog/2007/02/" title="February 2007">February 2007</a></li> <li><a href="/blog/2007/01/" title="January 2007">January 2007</a></li> </ul> </div> <!-- /grid_4 --> <div class="clear"> </div> </div> </div><!-- nonFooter end --> <div id="footer"> <div class="vcard contact" > <a class="url fn" href="http://ericholscher.com">Eric Holscher</a><br /> <a class="email" href="mailto:eric@ericholscher.com">eric@ericholscher.com</a><br /> <div class="adr"> <span class="locality">Lawrence</span> , <span class="region">Kansas</span> </div> <div class="tel">(757) 705 0532</div> </div> <!-- vcard End --> <div class="logo"> <a href="http://djangopony.com/" class="ponybadge" title="Magic! Ponies! Django! Whee!"> <img src="http://media.djangopony.com/img/small/badge.png" width="210" height="65" alt="ponybadge" /> </a> </div> <div class="clear"> </div> </div> <!-- Footer End --> <script type="text/javascript"> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); </script> <script type="text/javascript"> var pageTracker = _gat._getTracker("UA-1167735-1"); pageTracker._initData(); pageTracker._trackPageview(); </script> </body> </html>