<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Build</title>
	<atom:link href="http://thebuild.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://thebuild.com/blog</link>
	<description>programming, etc.</description>
	<lastBuildDate>Sun, 18 Jul 2010 20:34:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ORMs and Their Discontents: PGXPUG Day OSCON 2010 Presentation</title>
		<link>http://thebuild.com/blog/2010/07/18/orms-and-their-discontents-2/</link>
		<comments>http://thebuild.com/blog/2010/07/18/orms-and-their-discontents-2/#comments</comments>
		<pubDate>Sun, 18 Jul 2010 20:34:14 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=182</guid>
		<description><![CDATA[Here are the slides for my talk at PGXPUG Day OSCON 2010.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://thebuild.com/presentations/orms-and-their-discontents-oscon2010.pdf">Here are the slides</a> for my talk at PGXPUG Day OSCON 2010.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2010/07/18/orms-and-their-discontents-2/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Introduction to PostgreSQL: Open Source Bridge 2010 Presentation</title>
		<link>http://thebuild.com/blog/2010/06/03/introduction-to-postgresql-osb2010/</link>
		<comments>http://thebuild.com/blog/2010/06/03/introduction-to-postgresql-osb2010/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 20:30:20 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=178</guid>
		<description><![CDATA[The slides from my talk, Introduction to PostgreSQL are available here.
]]></description>
			<content:encoded><![CDATA[<p>The slides from my talk, <a href="http://thebuild.com/presentations/intro-to-postgresql-osb2010.pdf">Introduction to PostgreSQL</a> are available <a href="http://thebuild.com/presentations/intro-to-postgresql-osb2010.pdf">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2010/06/03/introduction-to-postgresql-osb2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SFPUG: Hot Standby and Streaming Replication</title>
		<link>http://thebuild.com/blog/2010/05/06/sfpug-hot-standby-and-streaming-replication/</link>
		<comments>http://thebuild.com/blog/2010/05/06/sfpug-hot-standby-and-streaming-replication/#comments</comments>
		<pubDate>Thu, 06 May 2010 21:19:37 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=174</guid>
		<description><![CDATA[The archive video for the February 9, 2010 SFPUG meeting is now available:


    
    
    
    
    


For downloading, the direct link is here.

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
]]></description>
			<content:encoded><![CDATA[<p>The archive video for the February 9, 2010 SFPUG meeting is now available:
<span id="more-174"></span>
<object classid='clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b' width="640" height="496" codebase='http://www.apple.com/qtactivex/qtplugin.cab'>
    <param name='src' value="http://media.postgresql.org/sfpug/sfpug-hssr-20100209.mov">
    </param><param name='autoplay' value="false">
    </param><param name='controller' value="true">
    </param><param name='loop' value="false">
    <embed src="http://media.postgresql.org/sfpug/sfpug-hssr-20100209.mov" width="640" height="496" autoplay="false" controller="true" loop="false" bgcolor="#000000" pluginspage='http://www.apple.com/quicktime/download/'>
</embed></param></object></p>

<p>For downloading, the <a href="http://media.postgresql.org/sfpug/sfpug-hssr-20100209.mov">direct link is here</a>.</p>

<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2010/05/06/sfpug-hot-standby-and-streaming-replication/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://media.postgresql.org/sfpug/sfpug-hssr-20100209.mov" length="527966887" type="video/quicktime" />
		</item>
		<item>
		<title>On switching away from Core Data</title>
		<link>http://thebuild.com/blog/2010/02/28/on-switching-away-from-core-data/</link>
		<comments>http://thebuild.com/blog/2010/02/28/on-switching-away-from-core-data/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 02:46:02 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=166</guid>
		<description><![CDATA[Brent Simmons has a very good piece about switching away from using Core Data to using SQLite directly in his iPhone app. Substituting &#8220;any common ORM&#8221; for &#8220;Core Data&#8221; (which, after all, is all Core Data is) and &#8220;any SQL database&#8221; for SQLite, he encounters the most common problems that plague those trying to develop [...]]]></description>
			<content:encoded><![CDATA[<p>Brent Simmons has a <a href="http://inessential.com/2010/02/26/on_switching_away_from_core_data">very good piece</a> about switching away from using Core Data to using SQLite directly in his iPhone app. Substituting &#8220;any common ORM&#8221; for &#8220;Core Data&#8221; (which, after all, is all Core Data is) and &#8220;any SQL database&#8221; for SQLite, he encounters the most common problems that plague those trying to develop scalable solutions on top of ORMs.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2010/02/28/on-switching-away-from-core-data/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SFPUG: Operator Exclusion Constraints</title>
		<link>http://thebuild.com/blog/2009/12/23/sfpug-operator-exclusion-constraints/</link>
		<comments>http://thebuild.com/blog/2009/12/23/sfpug-operator-exclusion-constraints/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 20:21:41 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=164</guid>
		<description><![CDATA[The archive video for the December 8, 2009 SFPUG meeting is now available:


    
    
    
    
    


For downloading, the direct link is here.

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
]]></description>
			<content:encoded><![CDATA[<p>The archive video for the December 8, 2009 SFPUG meeting is now available:
<span id="more-164"></span>
<object classid='clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b' width="640" height="496" codebase='http://www.apple.com/qtactivex/qtplugin.cab'>
    <param name='src' value="http://media.postgresql.org/sfpug/sfpug-exclusion-20091208.mov">
    </param><param name='autoplay' value="false">
    </param><param name='controller' value="true">
    </param><param name='loop' value="false">
    <embed src="http://media.postgresql.org/sfpug/sfpug-exclusion-20091208.mov" width="640" height="496" autoplay="false" controller="true" loop="false" bgcolor="#000000" pluginspage='http://www.apple.com/quicktime/download/'>
</embed></param></object></p>

<p>For downloading, the <a href="http://media.postgresql.org/sfpug/sfpug-exclusion-20091208.mov">direct link is here</a>.</p>

<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/12/23/sfpug-operator-exclusion-constraints/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
<enclosure url="http://media.postgresql.org/sfpug/sfpug-exclusion-20091208.mov" length="404880133" type="video/quicktime" />
		</item>
		<item>
		<title>SFPUG: Continuent Tungsten with PostgreSQL</title>
		<link>http://thebuild.com/blog/2009/12/22/sfpug-continuent-tungsten-with-postgresql/</link>
		<comments>http://thebuild.com/blog/2009/12/22/sfpug-continuent-tungsten-with-postgresql/#comments</comments>
		<pubDate>Tue, 22 Dec 2009 23:02:34 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=159</guid>
		<description><![CDATA[The archive video for the November 10, 2009 SFPUG meeting is now available:


    
    
    
    
    


For downloading, the direct link is here.

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
]]></description>
			<content:encoded><![CDATA[<p>The archive video for the November 10, 2009 SFPUG meeting is now available:
<span id="more-159"></span>
<object classid='clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b' width="640" height="496" codebase='http://www.apple.com/qtactivex/qtplugin.cab'>
    <param name='src' value="http://media.postgresql.org/sfpug/sfpug-tungsten-20091110.mov">
    </param><param name='autoplay' value="false">
    </param><param name='controller' value="true">
    </param><param name='loop' value="false">
    <embed src="http://media.postgresql.org/sfpug/sfpug-tungsten-20091110.mov" width="640" height="496" autoplay="false" controller="true" loop="false" bgcolor="#000000" pluginspage='http://www.apple.com/quicktime/download/'>
</embed></param></object></p>

<p>For downloading, the <a href="http://media.postgresql.org/sfpug/sfpug-tungsten-20091110.mov">direct link is here</a>.</p>

<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/12/22/sfpug-continuent-tungsten-with-postgresql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://media.postgresql.org/sfpug/sfpug-tungsten-20091110.mov" length="570500736" type="video/quicktime" />
		</item>
		<item>
		<title>Django, PostgreSQL, and Autocommit</title>
		<link>http://thebuild.com/blog/2009/11/07/django-postgresql-and-autocommit/</link>
		<comments>http://thebuild.com/blog/2009/11/07/django-postgresql-and-autocommit/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 02:23:04 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=144</guid>
		<description><![CDATA[In part 1, we ran down a list of the standard Django features for controlling transactions.  Now, we&#8217;re going to look at some ways to optimize how these tranactions happen.



Let&#8217;s look at the SQL that our create_order() view function generated, with the transaction middleware turned on, and no transaction decorators on the function:

LOG:  [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://thebuild.com/blog/2009/11/07/django-postgresql-and-transaction-management/">part 1</a>, we ran down a list of the standard Django features for controlling transactions.  Now, we&#8217;re going to look at some ways to optimize how these tranactions happen.</p>

<p><span id="more-144"></span></p>

<p>Let&#8217;s look at the SQL that our <code>create_order()</code> view function generated, with the <a href="http://docs.djangoproject.com/en/dev/topics/db/transactions/#tying-transactions-to-http-requests">transaction middleware</a> turned on, and no <a href="http://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views">transaction decorators</a> on the function:</p>

<pre><code>LOG:  statement: SET DATESTYLE TO 'ISO'
LOG:  statement: SHOW client_encoding
LOG:  statement: SHOW default_transaction_isolation
LOG:  statement: BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED
LOG:  statement: SET TIME ZONE E'America/Los_Angeles'
LOG:  statement: SELECT version()
LOG:  statement: INSERT INTO "example_address" ("street_address", "city", "state", "zip") VALUES (E'1313 Mockingbird Lane', E'Mockingbird Heights', E'CA', E'90026')
LOG:  statement: SELECT CURRVAL('"example_address_id_seq"')
LOG:  statement: INSERT INTO "example_order" ("customer_name", "shipping_address_id") VALUES (E'Herman Munster', 5)
LOG:  statement: SELECT CURRVAL('"example_order_id_seq"')
LOG:  statement: COMMIT
</code></pre>

<p>Setting aside the overhead statements (and, good grief, there are a lot of those), what&#8217;s wrong with this?  Well, not much, except that as of 8.2, PostgreSQL has a much better way of getting the primary key (or any other field, for that matter) back from an INSERT statement, which is the INSERT &#8230; RETURNING construct.  It&#8217;s perfect for just this situation, when you&#8217;re inserting a record and creating the primary key at the same time, and want to et the primary key back for further operations.</p>

<p>Now, let&#8217;s look at the SQL we get from our <code>show_order()</code> function:</p>

<pre><code>LOG:  statement: SET DATESTYLE TO 'ISO'
LOG:  statement: SHOW client_encoding
LOG:  statement: SHOW default_transaction_isolation
LOG:  statement: BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED
LOG:  statement: SET TIME ZONE E'America/Los_Angeles'
LOG:  statement: SELECT version()
LOG:  statement: SELECT "example_order"."id", "example_order"."customer_name", "example_order"."shipping_address_id" FROM "example_order" WHERE "example_order"."id" = 1 
LOG:  statement: ROLLBACK
</code></pre>

<p>In this case, we don&#8217;t need that transaction at all.</p>

<p>At it happens, there&#8217;s a Django feature that can address both these problems at once, as long as you are running PostgreSQL 8.2 with the <code>postgresql_psycopg2</code> backend&#8230;</p>

<h4>Enter the autocommit</h4>

<p>This functionality is kind of buried in the Django documentation, almost apologically stuck in the <a href="http://docs.djangoproject.com/en/dev/ref/databases/#autocommit-mode">Notes about supported databases</a> section.  It&#8217;s an option you add to your <code>settings.py</code> file:</p>

<pre><code>DATABASE_OPTIONS = {
    "autocommit": True,
}
</code></pre>

<p>What does this do?  The documentation, I&#8217;m afraid, is pretty obscure about the actual effect.  Groveling around in the code, we discover that what it does is prevent Django from automatically starting a new transaction on the first database operation.  If we switch it on, our SQL traffic for <code>show_order()</code> now looks like:</p>

<pre><code>LOG:  statement: SET DATESTYLE TO 'ISO'
LOG:  statement: SHOW client_encoding
LOG:  statement: SHOW default_transaction_isolation
LOG:  statement: SET TIME ZONE E'America/Los_Angeles'
LOG:  statement: SELECT version()
LOG:  statement: SELECT "example_order"."id", "example_order"."customer_name", "example_order"."shipping_address_id" FROM "example_order" WHERE "example_order"."id" = 1 
</code></pre>

<p>That&#8217;s much better!  Well, how about for <code>create_order</code>?</p>

<pre><code>Environment:

Request Method: GET
Request URL: http://127.0.0.1:8000/createorder/
Django Version: 1.1
Python Version: 2.5.2
Installed Applications:
['djangotrans.example']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware')


Traceback:
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/transaction.py" in _commit_on_success
  240.                 res = func(*args, **kw)
File "/Users/xof/Documents/Dev/examples/djangotrans/../djangotrans/example/views.py" in create_order
  9.     address.save()
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/base.py" in save
  410.         self.save_base(force_insert=force_insert, force_update=force_update)
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/base.py" in save_base
  495.                     result = manager._insert(values, return_id=update_pk)
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/manager.py" in _insert
  177.         return insert_query(self.model, values, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/query.py" in insert_query
  1087.     return query.execute_sql(return_id)
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/models/sql/subqueries.py" in execute_sql
  324.             return self.connection.ops.fetch_returned_insert_id(cursor)
File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/django/db/backends/__init__.py" in fetch_returned_insert_id
  171.         return cursor.fetchone()[0]

Exception Type: ProgrammingError at /createorder/
Exception Value: no results to fetch
</code></pre>

<p>Hm.  That&#8217;s not what we expected, at all.</p>

<p>As it happens, there&#8217;s a bug in Django 1.1 when using autocommit; it blows up if the very first thing that you do on a new database connection is an INSERT that expects a return value back.  As a workaround, we can add a line to our <code>create_order()</code> function to force it to do some traffic before the first insert:</p>

<pre><code>def create_order(request):
    cur = connection.cursor()
        # Work around Django 1.1 autocommit bug

    address = Address(street_address="1112 E Broad St", city="Westfield", state="NJ", zip="07090")
    address.save()

    order = Order(customer_name="Gomez Addams", shipping_address=address)
    order.save()

    return HttpResponse("Created: " + unicode(order))
</code></pre>

<p>And now, we get&#8230;</p>

<pre><code>LOG:  statement: SET DATESTYLE TO 'ISO'
LOG:  statement: SHOW client_encoding
LOG:  statement: SHOW default_transaction_isolation
LOG:  statement: SET TIME ZONE E'America/Los_Angeles'
LOG:  statement: SELECT version()
LOG:  statement: INSERT INTO "example_address" ("street_address", "city", "state", "zip") VALUES (E'1112 E Broad St', E'Westfield', E'NJ', E'07090') RETURNING "example_address"."id"
LOG:  statement: INSERT INTO "example_order" ("customer_name", "shipping_address_id") VALUES (E'Gomez Addams', 82) RETURNING "example_order"."id"
</code></pre>

<p>Wow, that&#8217;s great!  Notice the nice, efficient RETURNING clause, and notice&#8230; uh, the complete lack of a transaction block around the INSERTs.  This is why this particular function is called &#8220;autocommit&#8221;: since we&#8217;re not running inside an enclosing transaction, each statement is &#8220;autocommitted&#8221; upon completion.  (Calling a feature &#8220;autocommit&#8221; when the practical effect is that the framework does not automatically generate <code>COMMIT</code> statements is perhaps not the best choice of nomenclature.)</p>

<p>So, what are our options?  Let&#8217;s add the <code>@transaction.commit_on_success</code> decorator, and see if that improves matters:</p>

<pre><code>LOG:  statement: SET DATESTYLE TO 'ISO'
LOG:  statement: SHOW client_encoding
LOG:  statement: SHOW default_transaction_isolation
LOG:  statement: BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED
LOG:  statement: SET TIME ZONE E'America/Los_Angeles'
LOG:  statement: SELECT version()
LOG:  statement: INSERT INTO "example_address" ("street_address", "city", "state", "zip") VALUES (E'1112 E Broad St', E'Westfield', E'NJ', E'07090') RETURNING "example_address"."id"
LOG:  statement: INSERT INTO "example_order" ("customer_name", "shipping_address_id") VALUES (E'Gomez Addams', 84) RETURNING "example_order"."id"
LOG:  statement: COMMIT
</code></pre>

<p>Perfect.</p>

<h4>Wait.  What&#8217;s going on?</h4>

<p>The following is a digression, and isn&#8217;t really required to use <code>autocommit</code>&#8230; but you might find it interesting.</p>

<p>You might well be thinking, &#8220;That&#8217;s all a very nifty trick, but what in the world does <code>INSERT ... RETURNING</code> have to do with autocommit?  And why is <code>autocommit</code> limited to PostgreSQL 8.2, when that behavior has been standard with PostgreSQL since ever?&#8221;</p>

<p>First, note how Django gets the result of an INSERT if it does have the INSERT &#8230; RETURNING syntax available:</p>

<pre><code>LOG:  statement: INSERT INTO "example_address" ("street_address", "city", "state", "zip") VALUES (E'1313 Mockingbird Lane', E'Mockingbird Heights', E'CA', E'90026')
LOG:  statement: SELECT CURRVAL('"example_address_id_seq"')
</code></pre>

<p>That is, it calls the <code>currval</code> function.  This works great&#8230; as long as you are assured that you are the same connection as you were when you issued the insert.  But why wouldn&#8217;t you be?</p>

<p>Good question, and the answer is: Pooling.</p>

<p>Pretty much any site with any degree of load will, at some point, need pooling software like <a href="http://pgpool.projects.postgresql.org/">pgpool-II</a> or <a href="https://developer.skype.com/SkypeGarage/DbProjects/PgBouncer">PgBouncer</a> to multiplex connections between the application and database server.  </p>

<p>The base mode on both of these fine products simulates as closely as possible being directly connected to the database: Each time the client connects to the intermediate connection pooler, it appears that a new, isolated connection has opened up.</p>

<p>However, more aggressive forms of connection pooling are possible.  For example, PgBouncer has transaction pooling, in which the connection to the database is only assigned to a client while it has a transaction open.  Between transactions, the connection between PgBouncer and the database could switch, which would cause (really strange and hard-to-reproduce) errors.</p>

<p>&#8220;But,&#8221; you say, having read the PgBouncer docs, &#8220;it&#8217;s inside a transaction!  That keep it from switching to a new connection, even when you&#8217;re using transaction pooling!&#8221;</p>

<p>That&#8217;s true&#8230; unless you are running with <code>autocommit</code> turned on, and take no special precautions to make sure that your INSERT is inside of a transation block (remember, it&#8217;s not by default, as we saw above).</p>

<p>Note that it is never <em>wrong</em> to use INSERT &#8230; RETURNING; it&#8217;s just <em>required</em> if you are using transaction pooling (Django doesn&#8217;t know if you are or not, so it assumes that you are), with <code>autocommit</code> turned on, and if you do not take special pains to put each INSERT or group thereof into its own transaction.</p>

<h4>Back to Reality.</h4>

<p>I have to say that it appears that Django&#8217;s <code>autocommit</code> support isn&#8217;t quite fully baked, but it&#8217;s still a very useful feature for getting rid of the redundant <code>BEGIN</code>/<code>ROLLBACK</code> blocks around read-only view functions (which will tend to be the majority of them), while still giving the programmer control over the commit model for those view functions that <em>do</em> write to the database.  And, as a nice little bonus, you get the more efficient <code>INSERT ... RETURNING</code> operation as well, as long as you are using PostgreSQL 8.2 or higher.  And, of course, <a href="http://www.postgresql.org/docs/8.4/static/release-8-4.html">you should be</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/11/07/django-postgresql-and-autocommit/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Django, PostgreSQL, and Transaction Management</title>
		<link>http://thebuild.com/blog/2009/11/07/django-postgresql-and-transaction-management/</link>
		<comments>http://thebuild.com/blog/2009/11/07/django-postgresql-and-transaction-management/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 21:40:59 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=134</guid>
		<description><![CDATA[Django has quite a bit of code in it devoted to transaction management.  Although the documentation goes into quite a bit of depth on transactions, I&#8217;ve never felt that the docs by themselves let you build a good mental model of how transactions actually work.  So, I decided to approach it experimentally: Build [...]]]></description>
			<content:encoded><![CDATA[<p>Django has quite a bit of code in it devoted to transaction management.  Although the documentation <a href="http://docs.djangoproject.com/en/dev/topics/db/transactions/">goes into quite a bit of depth on transactions</a>, I&#8217;ve never felt that the docs by themselves let you build a good mental model of how transactions actually work.  So, I decided to approach it experimentally: Build a small Django app, and see how the various options actually work.</p>

<p><span id="more-134"></span></p>

<p>For all of this, I&#8217;m using Django 1.1.1 and PostgreSQL 8.4.1, through the psycopg2 interface.</p>

<p>For the application, we have a <code>models.py</code>:</p>

<pre><code>from django.db import models

class Address(models.Model):
    street_address = models.CharField(max_length=80)
    city = models.CharField(max_length=80)
    state = models.CharField(max_length=2)
    zip = models.CharField(max_length=5)

    def __unicode__(self):
        return self.street_address + " " + self.city + " " + self.state + " " + self.zip

class Order(models.Model):
    customer_name = models.CharField(max_length=80)
    shipping_address = models.ForeignKey(Address)

    def __unicode__(self):
        return "Order " + unicode(self.id) + " going to " + \
            self.customer_name + ", " + unicode(self.shipping_address)
</code></pre>

<p>and a <code>views.py</code>:</p>

<pre><code>from django.http import HttpResponse
from djangotrans.example.models import Order, Address
from django.db import transaction, connection

def create_order(request):

    address = Address(street_address="1112 E Broad St", city="Westfield", state="NJ", zip="07090")
    address.save()

    order = Order(customer_name="Gomez Addams", shipping_address=address)
    order.save()

    return HttpResponse("Created: " + unicode(order))


def show_order(request, order_id):
    order = Order.objects.get(pk=order_id)

    return HttpResponse(unicode(order))
</code></pre>

<p>and a <code>urls.py</code>:</p>

<pre><code>from django.conf.urls.defaults import *

urlpatterns = patterns('djangotrans.example.views',
    (r'^createorder/$', 'create_order'),
    (r'^showorder/(?P&lt;order_id&gt;\d+)$', 'show_order'),

)
</code></pre>

<h4>The Basic Rule</h4>

<p>In absence of any mention of transaction management at all, Django opens a new transaction with each database operation, and closes it when the operation is complete.  If all you do is read operations on the model, it does a <code>ROLLBACK</code> to close the transaction; if you do a data-changing operation, it does a <code>COMMIT</code>.  For example, in <code>create_order</code>, the pattern looks something like:</p>

<pre><code># BEGIN
address = Address(street_address="1112 E Broad St", city="Westfield", state="NJ", zip="07090")
address.save()
# COMMIT

# BEGIN
order = Order(customer_name="Gomez Addams", shipping_address=address)
order.save()
# COMMIT
</code></pre>

<p>&#8230; and in <code>show_order</code>:</p>

<pre><code># BEGIN
order = Order.objects.get(pk=order_id)
# ROLLBACK
</code></pre>

<p>This is simple, straight-forward&#8230; and wrong.  The two operations in <code>save_order</code> should be wrapped in a single transaction.  If we saved the address, but didn&#8217;t then save the order, we&#8217;d have an &#8220;orphan&#8221; address, and that would be just tragic.  So, what to do?  Fortunately, Django provides a rather large toolbox full of other ways of managing transactions.</p>

<h4>Transaction Middleware</h4>

<p>First, let&#8217;s take a look at the <a href="http://docs.djangoproject.com/en/dev/topics/db/transactions/#tying-transactions-to-http-requests">transaction middleware</a>.  This is a <a href="http://docs.djangoproject.com/en/dev/topics/http/middleware/">middleware component</a> that you add to <code>settings.py</code>:</p>

<pre><code>MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.transaction.TransactionMiddleware',
)
</code></pre>

<p>This component sets a flag in Django turning off the automatic <code>COMMIT</code>/<code>ROLLBACK</code> behavior, and instead does an automatic <code>BEGIN</code> when each request starts, and then a <code>COMMIT</code> (if the view function returns normally and did a data-changing operation) or <code>ROLLBACK</code> (when the view function throws an exception, or returns normally having not modified data.)</p>

<p>Doing this to our extremely sophisticated application above, we get a much more pleasing pattern of transaction management:</p>

<pre><code># BEGIN
address = Address(street_address="1112 E Broad St", city="Westfield", state="NJ", zip="07090")
address.save()

order = Order(customer_name="Gomez Addams", shipping_address=address)
order.save()
# COMMIT
</code></pre>

<p>&#8230; and in <code>show_order</code>:</p>

<pre><code># BEGIN
order = Order.objects.get(pk=order_id)
# ROLLBACK
</code></pre>

<p>Much better.</p>

<h4>Transaction Decorators</h4>

<p>Django provides a set of <a href="http://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views">transaction decorators</a> that can be added to view functions to explicitly control how transactions work for that particular function.  They work the same way whether or not the transaction middleware is present.  They are:</p>

<ul>
<li><strong>@transaction.autocommit</strong> &#8212; This sets the default Django behavior: A <code>COMMIT</code> after each <code>save()</code>, and a <code>ROLLBACK</code> after each database read.  If the transaction middleware isn&#8217;t present, this doesn&#8217;t do anything; if the transaction middleware is present, this reverts this particular function back to the default behavior.</li>
<li><strong>@transaction.commit&#95;on&#95;success</strong> &#8212; This sets the transaction middleware behavior of commiting all of the work done in a single view method (if data modification occurs and the view returns successfully), or doing a single <code>ROLLBACK</code> at the end (if data modification does not occur, or the method throws an exception). It&#8217;s redunant if the transaction middleware is enabled.</li>
<li><strong>@transaction.commit_manually</strong> &#8212; This overrides the current transaction behavior, and requires that the view function call either <code>transaction.commit()</code> or <code>transaction.rollback()</code> at the appropriate place or places (they can be called multiple times within a single view function). If a view function exits with data-modifying work done after the last <code>commit()</code> or <code>rollback()</code> call, the decorator will throw a <code>TransactionManagementError</code> exception.</li>
</ul>

<h4>So, What&#8217;s Not to Like?</h4>

<p>That seems to be a pretty comprehensive set of transaction control mechanisms.  So, what else could one want?  Let&#8217;s take a look at what is actually sent to the database when we show an order:</p>

<pre><code>LOG:  statement: SET DATESTYLE TO 'ISO'
LOG:  statement: SHOW client_encoding
LOG:  statement: SHOW default_transaction_isolation
LOG:  statement: BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED
LOG:  statement: SET TIME ZONE E'America/Los_Angeles'
LOG:  statement: SELECT "example_order"."id", "example_order"."customer_name", "example_order"."shipping_address_id" FROM "example_order" WHERE "example_order"."id" = 47 
LOG:  statement: SELECT "example_address"."id", "example_address"."street_address", "example_address"."city", "example_address"."state", "example_address"."zip" FROM "example_address" WHERE "example_address"."id" = 79 
LOG:  statement: ROLLBACK
</code></pre>

<p>The transaction here isn&#8217;t actually required at all, setting aside the other overhead.  Can we get rid of it?  In <a href="http://thebuild.com/blog/2009/11/07/django-postgresql-and-autocommit/">part two</a>, we&#8217;ll see how we can.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/11/07/django-postgresql-and-transaction-management/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ORMs and Their Discontents</title>
		<link>http://thebuild.com/blog/2009/11/04/orms-and-their-discontents/</link>
		<comments>http://thebuild.com/blog/2009/11/04/orms-and-their-discontents/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 03:13:44 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=130</guid>
		<description><![CDATA[I love object-oriented programming.  The first time I ever encountered an OO language or framework (Object Pascal and MacApp, thank you for asking), it was as if the heavens opened.  It simply made sense to me as a way of structuring programs, and I&#8217;ve been wedded to it ever since.  (As it [...]]]></description>
			<content:encoded><![CDATA[<p>I love object-oriented programming.  The first time I ever encountered an OO language or framework (Object Pascal and MacApp, thank you for asking), it was as if the heavens opened.  It simply made sense to me as a way of structuring programs, and I&#8217;ve been wedded to it ever since.  (As it turns out, if you do the right paperwork, you <em>can</em> marry a concept.)</p>

<p>So, I think object-oriented programming is the bee&#8217;s knees.  And, in this post, I&#8217;m going to tell you to not use it.</p>

<p><span id="more-130"></span></p>

<p>I was recently working on a Django application, using PostgreSQL as the database.  (This application has been heavily anonymized.)   Among many other things, it has a table that is, in essence, a work flow queue.  The queue is a list of orders, based on their (integer) primary key, order_pk.  Periodically, a task comes through, reads the queue into a Python list, and runs down it, calling a method on each object:</p>

<pre><code>for queue_entry in order_queue
    order = Orders.objects.get(pk=queue_entry.order_pk)
    order.allocate_inventory()
</code></pre>

<p>What does <code>allocate_inventory()</code> do?  It calls a stored procedure, and returns:</p>

<pre><code>def allocate_inventory(self):
    cursor = connection.cursor()
    cursor.execute("""
        SELECT allocate_inventory(%s)
    """, [self.pk])
</code></pre>

<p>Lovely!  Let&#8217;s just look at the database traffic it creates and&#8230; oh, gross.</p>

<p>The program is reading in and instantiating an entire <code>order</code> object, so it can get the primary key out of it.  But the way it was able to instantiate the object was because it had the primary key.  In this application, <code>order</code> objects have lots and lots of fields, so it&#8217;s dragging all of those fields across the wire to build the object, only to use the one field we already knew before we even creted the object.</p>

<p>If everything was in memory, no problem.  Instatiating a Python object isn&#8217;t free, but it&#8217;s no big deal, and this keeps everything nicely encapsulated.  But this is one of the dangers of ORMs: Things that would be cheap in an in-memory world suddenly become much pricier when you have to go out to the database, and it can be somewhat non-obvious when you have to go out to the database, how many times, and in what particular way.</p>

<p>(In one particularly pathological example, in this same application, the Django ORM was doing <em>seven</em> calls to the database in order to populate one pop-up menu &#8230; which had exactly one entry in it.)</p>

<p>The fix, of course, is to pass the primary key around rather than object:</p>

<pre><code>for queue_entry in order_queue
    allocate_inventory(queue_entry.order_pk)

@staticmethod
def allocate_inventory(order_pk):
    cursor = connection.cursor()
    cursor.execute("""
        SELECT orders.allocate_inventory(%s)
    """, [order_pk])
</code></pre>

<p>&#8230; even though this isn&#8217;t nearly as clean from an OO perspective as creating the object.</p>

<p>Whenever you&#8217;re developing against kind of ORM (or, really, any database application programming at all), it&#8217;s very wise to set all of the logging on the development PostgreSQL server to &#8220;log every statement,&#8221; and keep a <code>tail -f</code> of the log file going in another window.  That way, if an operation that looks like the proverbial &#8220;just a few lines of code&#8221; generates an unexpectedly large number of database calls, you can address that before it falls over in production.</p>

<p>ORMs can be very powerful, but the typical usage patterns in a nicely structured OO program can interact with them very badly, and generate a lot more database traffic than you&#8217;d expect.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/11/04/orms-and-their-discontents/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Git vs Mercurial</title>
		<link>http://thebuild.com/blog/2009/11/04/git-vs-mercurial/</link>
		<comments>http://thebuild.com/blog/2009/11/04/git-vs-mercurial/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 19:22:00 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=126</guid>
		<description><![CDATA[No, I&#8217;m not going to write another Git vs Mercurial post that really digs into them, because&#8230; well, if you are using one or the other, it is probably for reasons that don&#8217;t have much to do with your preferences.

In strictly my opinion, for personal use, I like Mercurial. For projects that use Git, I [...]]]></description>
			<content:encoded><![CDATA[<p>No, I&#8217;m not going to write another Git vs Mercurial post that really digs into them, because&#8230; well, if you are using one or the other, it is probably for reasons that don&#8217;t have much to do with your preferences.</p>

<p>In strictly my opinion, for personal use, I like Mercurial. For projects that use Git, I use Git.</p>

<p>My two sentence summary is: Mercurial is your smart friend who likes to explain things to you. Git is your genius coworker who sighs and rolls his eyes every time you ask him a question.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/11/04/git-vs-mercurial/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WordPress to Django+PostgreSQL, Part 4: Configuring Apache, Django, PostgreSQL</title>
		<link>http://thebuild.com/blog/2009/10/19/wordpress-to-djangopostgresql-part-4-configuring-apache-django-postgresql/</link>
		<comments>http://thebuild.com/blog/2009/10/19/wordpress-to-djangopostgresql-part-4-configuring-apache-django-postgresql/#comments</comments>
		<pubDate>Mon, 19 Oct 2009 15:30:35 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=110</guid>
		<description><![CDATA[In the previous installment of this series (in which we&#8217;re migrating this blog from WordPress to Django and PostgreSQL), we installed Apache, Python 2.6, psycopg and mod_wsgi on the server.

A note about the pace: I&#8217;m taking this very slowly, spelling out each and every setp. I realize that those of you with more Centos experience [...]]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-3-installing-apache-python-2-6-psycopg2-and-mod_wsgi/">previous installment</a> of this series (in which we&#8217;re migrating this blog from WordPress to Django and PostgreSQL), we installed Apache, Python 2.6, <code>psycopg</code> and <code>mod_wsgi</code> on the server.
<span id="more-110"></span>
A note about the pace: I&#8217;m taking this very slowly, spelling out each and every setp. I realize that those of you with more Centos experience (which is probably pretty much everyone) or Django experience are probably tapping your feet and thinking, &#8220;Come <em>on</em>, get a move on here!&#8221;  To those, I beg your indulgence.  When reading about a topic I am unfamiliar with, I appreciate a high level of detail, so I don&#8217;t hit a weird error message only to be told, &#8220;Oh, right, you have to install an old version of x.  I skipped that step.&#8221;</p>

<h4>Installing Django</h4>

<p>We have choices here: We can install Django directly from the current Subversion repository, or from an official release.  We also have the choice of installing Django as local to a particular user, or global for the whole system.  For this install, we&#8217;ll do an official release (1.1.1 is current), and install it for the whole system.</p>

<pre><code>[xof@blog ~]$ cd builds
[xof@blog builds]$ wget http://www.djangoproject.com/download/1.1.1/tarball/
[xof@blog builds]$ tar xvfz Django-1.1.1.tar.gz
[xof@blog builds]$ cd Django-1.1.1
[xof@blog Django-1.1.1]$ sudo python2.6 setup.py install
[xof@blog Django-1.1.1]$ python2.6
Python 2.6.3 (r263:75183, Oct 17 2009, 18:29:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; import django
&gt;&gt;&gt; 
</code></pre>

<h4>Where is the project going to live?</h4>

<p>Before we configure Apache and <code>mod_wsgi</code> to serve up our new Django project, we should decide where the project is going to live.  I like to keep my builds and maintenance account separate from the user that contains the actual stuff being served up by the web server&#8230; so let&#8217;s create a new user just to hold the project:</p>

<pre><code>[xof@blog ~]$ sudo /usr/sbin/adduser thebuild
[xof@blog ~]$ sudo passwd thebuild
[xof@blog ~]$ sudo /usr/sbin/usermod -a -G apache thebuild
</code></pre>

<p>Note: Depending on the permissions your installation sets on <code>/home</code> directories by default, you may need to adjust them so that <code>mod_wsgi</code> can get at the files it needs.</p>

<h4>Set up the Django project</h4>

<p>Logging in as the project user, first, we&#8217;ll make sure that we get the right Python installation by adding an alias to our <code>.bash_profile</code>:</p>

<pre><code>alias python='/usr/bin/python2.6'
</code></pre>

<p>Just checking!</p>

<pre><code>[thebuild@blog ~]$ which python
alias python='/usr/bin/python2.6'
    /usr/bin/python2.6
</code></pre>

<p>And we can now create the project:</p>

<pre><code>[thebuild@blog ~]$ cd thebuild.com
[thebuild@blog thebuild.com]$ python /opt/python2.6/lib/python2.6/site-packages/django/bin/django-admin.py startproject thebuild
</code></pre>

<p>We also need to create a directory for any Python eggs that our application might download (this is, by the way, a &#8220;feature&#8221; of Python that I really do not care for).</p>

<pre><code>[thebuild@blog thebuild.com]$ mkdir .python-eggs
[thebuild@blog thebuild.com]$ chmod 770 .python-eggs
</code></pre>

<p>Now, we need to create a .wsgi file.  The .wsgi file is the glue that connects the <code>mod_wsgi</code> module in Apache to our particular application.  The Django project itself doesn&#8217;t (and shouldn&#8217;t) live under the webroot of the web server, but the .wsgi file does:</p>

<pre><code>[thebuild@blog thebuild.com]$ cd ~/thebuild.com
[thebuild@blog ~]$ mkdir apache
[thebuild@blog ~]$ cd apache
[thebuild@blog apache]$ cat &gt;&gt;django.wsgi
#!/opt/python2.6/bin/python

import os, sys

sys.path.append('/home/thebuild/thebuild.com')

os.environ['DJANGO_SETTINGS_MODULE'] = 'thebuild.settings'
os.environ['PYTHON_EGG_CACHE'] = '/home/thebuild/thebuild.com/.python-eggs'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()
[thebuild@blog apache]$ 
</code></pre>

<p>Next, let&#8217;s create the media and admin-media directories, and move the admin media over from the source distribution:</p>

<pre><code>[thebuild@blog apache]$ mkdir admin-media
[thebuild@blog apache]$ mkdir media
[thebuild@blog apache]$ cd admin-media
[thebuild@blog admin-media]$ cp -R /opt/python2.6/lib/python2.6/site-packages/django/contrib/admin/media/* .
</code></pre>

<h4>Creating a User in PostgreSQL for the Blog</h4>

<p>Right now, the only user in the PostgreSQL cluster is the default superuser; that&#8217;s not a great choice for the user that Django will use to connect to the database.</p>

<p>It&#8217;s also not idea to allow the Django user to create objects in the <code>public</code> schema, but it needs to be able to create objects in <em>some</em> schema if we&#8217;re going to use the cool Django model mechanism for table and field creation.</p>

<p>First, let&#8217;s create a database for the site:</p>

<pre><code>[postgres@blog ~]$ createdb thebuild
[postgres@blog ~]$ psql thebuild
psql (8.4.1)
Type "help" for help.

thebuild=# CREATE USER django ENCRYPTED PASSWORD 'password';
CREATE ROLE
</code></pre>

<p>Then, let&#8217;s create a schema just to hold objects related to the site:</p>

<pre><code>thebuild=# CREATE SCHEMA thebuild AUTHORIZATION django;
CREATE SCHEMA
</code></pre>

<p>And set an appropriate search path:</p>

<pre><code>thebuild=# ALTER ROLE django SET search_path TO thebuild, public;
ALTER ROLE
</code></pre>

<p>&#8230; and revoke CREATE on the public schema from the user:</p>

<pre><code>thebuild=# REVOKE CREATE ON SCHEMA public FROM  django;
REVOKE
</code></pre>

<p>This means that, by default, anything that the <code>django</code> user creates will go into the schema <code>thebuild</code>, while it still has access to the schema <code>public</code>.  However, it won&#8217;t be able to create new objects in <code>public</code>.</p>

<p>(Note that we still have rather a barn door open here: We haven&#8217;t done anything with <code>pg_hba.conf</code> to require passwords or other security to log in.)</p>

<h4>Django Settings</h4>

<p>We&#8217;ll need to update the settings.py file to match all of the various changes we made. So far, we&#8217;ve changed:</p>

<pre><code>DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'thebuild'
DATABASE_USER = 'django'
DATABASE_PASSWORD = 'password'

TIME_ZONE = 'America/Los_Angeles'

MEDIA_ROOT = '/home/thebuild/thebuild.com/apache/media/'
MEDIA_URL = 'http://new.thebuild.com/media/'

ADMIN_MEDIA_PREFIX = '/admin-media/'

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
)
</code></pre>

<p>Note that we&#8217;ve turned on the admin site by adding <code>django.contrib.admin</code> to installed apps.  Now, we can do a <code>syncdb</code> to create the databases the installed apps require:</p>

<pre><code>thebuild@blog thebuild]$ python manage.py syncdb
Creating table django_admin_log
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

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use 'thebuild'): admin
E-mail address: xof@thebuild.com
Password: 
Password (again): 
Superuser created successfully.
Installing index for admin.LogEntry model
Installing index for auth.Permission model
Installing index for auth.Message model
[thebuild@blog thebuild]$ 
</code></pre>

<h4>Configure Apache</h4>

<p>Apache can be tweaked endlessly, of course, but we&#8217;re going to do the minimum required to get the server up and ticking.  Assuming we&#8217;ve done the basics (ServerName, etc.), we add the module info for <code>mod_wsgi</code>:</p>

<pre><code>LoadModule wsgi_module modules/mod_wsgi.so
AddHandler wsgi-script .wsgi
</code></pre>

<p>Now, we need to point to the .wsgi file we created above.  Moving over to <code>/etc/httpd/conf.d</code>, we can create a file <code>thebuild.conf</code> to contain the virtual host:</p>

<pre><code>&lt;IfModule mod_alias.c&gt;
    Alias /media /home/thebuild/thebuild.com/apache/media
    Alias /admin-media /home/thebuild/thebuild.com/apache/admin-media
&lt;/IfModule&gt;

&lt;IfModule mod_wsgi.c&gt;
    WSGIScriptAlias / /home/thebuild/thebuild.com/apache/django.wsgi
    WSGIDaemonProcess thebuild processes=5 threads=6 display-name=%{GROUP}
    WSGIProcessGroup thebuild
    WSGIApplicationGroup %{GLOBAL}

    WSGISocketPrefix run/wsgi
&lt;/IfModule&gt;
</code></pre>

<p>&#8230; restart Apache &#8230;</p>

<pre><code>[xof@blog conf]$ sudo /etc/init.d/httpd graceful
</code></pre>

<p>&#8230; and did it work?</p>

<p><img src="http://thebuild.com/blog/wp-content/uploads/2009/10/it-lives.png" alt="it-lives" title="it-lives" width="495" height="311" class="alignnone size-full wp-image-111" /></p>

<p>Exciting! Now, time to start actually designing our blog application.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/19/wordpress-to-djangopostgresql-part-4-configuring-apache-django-postgresql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress to Django+PostgreSQL, Part 3: Installing Apache, Python 2.6, psycopg2, and mod_wsgi</title>
		<link>http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-3-installing-apache-python-2-6-psycopg2-and-mod_wsgi/</link>
		<comments>http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-3-installing-apache-python-2-6-psycopg2-and-mod_wsgi/#comments</comments>
		<pubDate>Sat, 17 Oct 2009 23:09:48 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=102</guid>
		<description><![CDATA[In part 2 of this series, we got PostgreSQL up and running.  In this part, we&#8217;ll install the remaining components to get Django up and running under Apache: Apache itself, Python 2.6, psycopg2, and mod_wsgi.

So far, we&#8217;ve just accepted the default configuration parameters that initdb provided.  Those will get us up and running, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-2-configuring-postgresql/">In part 2 of this series</a>, we got PostgreSQL up and running.  In this part, we&#8217;ll install the remaining components to get Django up and running under Apache: Apache itself, Python 2.6, psycopg2, and <code>mod_wsgi</code>.
<span id="more-102"></span>
So far, we&#8217;ve just accepted the default configuration parameters that <code>initdb</code> provided.  Those will get us up and running, and setting the various PostgreSQL config parameters is worth at least one post all to itself.  (In the meantime, see Josh Berkus&#8217; talk <a href="http://thebuild.com/blog/2009/10/16/the-mighty-gucs/">&#8220;The Mighty GUCS&#8221;</a>.)</p>

<p>Installing Apache couldn&#8217;t be easier:</p>

<pre><code>[xof@blog ~]$ sudo yum install httpd httpd-devel
</code></pre>

<p>(We need <code>httpd-devel</code> to build <code>mod_wsgi</code>, the module we&#8217;ll use to get at Python programs from Apache.)</p>

<h4> Python and Centos: A Brief Diversion</h4>

<p>The good news about Python on Centos is that it comes pre-installed.  (It has to be; <code>yum</code>, among other tools, is written in Python.)  The bad news is that the version that it comes with is &#8230;</p>

<pre><code>[xof@blog ~]$ python -V
Python 2.4.3
</code></pre>

<p>&#8230; not exactly current.  The most recent version of Python on the 2.x line as of this writing is 2.6.3.  The very bad news is that you cannot just upgrade the base system Python install to 2.6; it breaks some of the system tools.</p>

<p>Fortunately, a solution exists: Doing a parallel installation of Python.  I&#8217;m deeply indebted to <a href="http://blog.perplexedlabs.com/2008/11/10/setup-python-25-mod_wsgi-and-django-10-on-centos-5-cpanel/">this posting from Perplexed Labs</a> for guidance on the process.</p>

<h4>On with it: Installing Python 2.6</h4>

<p>Since the RPMs for Centos are all Python 2.4, we need to install Python 2.6 from source.  So, we grab the tarball, download it, and install it.</p>

<pre><code>[xof@blog ~]$ cd builds
[xof@blog builds]$ wget http://www.python.org/ftp/python/2.6.3/Python-2.6.3.tgz
[xof@blog builds]$ tar xvfz Python-2.6.3.tgz
[xof@blog builds]$ cd Python-2.6.3
</code></pre>

<p>Note the <code>--prefix</code> option to put the 2.6 install in a different location.</p>

<pre><code>[xof@blog Python-2.6.3]$ ./configure --prefix=/opt/python2.6 --with-threads --enable-shared
[xof@blog Python-2.6.3]$ make
[xof@blog Python-2.6.3]$ sudo make install
</code></pre>

<p>Add a symbolic link to put Python 2.6 in our path:</p>

<pre><code>[xof@blog Python-2.6.3]$ sudo ln -s /opt/python2.6/bin/python /usr/bin/python2.6
</code></pre>

<p>Add the shared libraries to <code>ldconfig</code> and to <code>/usr/lib64</code>:</p>

<pre><code>[xof@blog Python-2.6.3]$ sudo sh
sh-3.2# cat &gt;&gt; /etc/ld.so.conf.d/opt-python2.6.conf
/opt/python2.6/lib
sh-3.2# /sbin/ldconfig
sh-3.2# exit
[xof@blog Python-2.6.3]$ cd /usr/lib64
[xof@blog Python-2.6.3]$ sudo ln -s /opt/python2.6/lib/libpython2.6.so.1.0 libpython2.6.so.1.0 
[xof@blog Python-2.6.3]$ sudo ln -s libpython2.6.so.1.0  libpython2.6.so
</code></pre>

<p>How does it look?</p>

<pre><code>[xof@blog Python-2.6.3]$ python2.6
Python 2.6.3 (r263:75183, Oct 17 2009, 18:29:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; 
</code></pre>

<p>Great. Onwards.</p>

<h4>Installing setuptools</h4>

<p>It&#8217;s very handy to have the Python package <a href="http://pypi.python.org/pypi/setuptools"><code>setuptools</code></a>, so let&#8217;s download that and install it from the appropriate Python egg:</p>

<pre><code>[xof@blog Python-2.6.3]$ cd ..
[xof@blog builds]$ wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c9-py2.6.egg
[xof@blog builds]$ sudo sh setuptools-0.6c9-py2.6.egg --prefix=/opt/python2.6
</code></pre>

<h4>Installing psycopg2</h4>

<p>And now we can install <a href="http://initd.org/"><code>psycopg2</code></a>. First, I have to say that the documentation on pretty much any aspect of <code>psycopg2</code> is not exactly everything one can ask for; reading the INSTALL file in the tarball is your friend&#8230;</p>

<pre><code>[xof@blog builds]$ wget http://initd.org/pub/software/psycopg/psycopg2-2.0.13.tar.gz
[xof@blog builds]$ tar xvfz psycopg2-2.0.13.tar.gz
[xof@blog builds]$ cd psycopg2-2.0.13
</code></pre>

<p>One of the files in the tarball is <code>setup.cfg</code>; this contains a setting we need to fix. We point pg_config to the right location for the binary.</p>

<pre><code># "pg_config" is the preferred method to locate PostgreSQL headers and
# libraries needed to build psycopg2. If pg_config is not in the path or
# is installed under a different name uncomment the following option and
# set it to the pg_config full path.
pg_config=/usr/local/pgsql/bin/pg_config
</code></pre>

<p>And away we go!</p>

<pre><code>[xof@blog psycopg2-2.0.13]$ python2.6 setup.py build
[xof@blog psycopg2-2.0.13]$ sudo python2.6 setup.py install
</code></pre>

<p>So, did <em>that</em> work?</p>

<pre><code>[xof@blog psycopg2-2.0.13]$ python2.6
Python 2.6.3 (r263:75183, Oct 17 2009, 18:29:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; import psycopg2
&gt;&gt;&gt; conn = psycopg2.connect("dbname='template1' user='postgres' host='localhost'")
&gt;&gt;&gt; cur = conn.cursor()
&gt;&gt;&gt; cur.execute("""SELECT datname from pg_database""")
&gt;&gt;&gt; rows = cur.fetchall()
&gt;&gt;&gt; print rows
[('template1',), ('template0',), ('postgres',)]
</code></pre>

<h4>Installing mod_wsgi</h4>

<p><a href="http://code.google.com/p/modwsgi/"><code>mod_wsgi</code></a> is an Apache module serving up Python programs.  It&#8217;s generally considered a superior candidate to <code>mod_python</code>.</p>

<pre><code>[xof@blog builds]$ wget http://modwsgi.googlecode.com/files/mod_wsgi-2.6.tar.gz
[xof@blog builds]$ tar xvfz mod_wsgi-2.6.tar.gz
[xof@blog builds]$ cd mod_wsgi-2.6
[xof@blog mod_wsgi-2.6]$ ./configure --with-python=/opt/python2.6/bin/python
[xof@blog mod_wsgi-2.6]$ make
[xof@blog mod_wsgi-2.6]$ sudo make install
</code></pre>

<p>To be paranoid, we should check two things.  One: Did it link against the correct Python shared library?</p>

<pre><code>xof@blog mod_wsgi-2.6]$ ldd /usr/lib64/httpd/modules/mod_wsgi.so
    linux-vdso.so.1 =&gt;  (0x00007fffcbbfe000)
    libpython2.6.so.1.0 =&gt; /opt/python2.6/lib/libpython2.6.so.1.0 (0x00007f9ac3553000)
    libpthread.so.0 =&gt; /lib64/libpthread.so.0 (0x00007f9ac332c000)
    libdl.so.2 =&gt; /lib64/libdl.so.2 (0x00007f9ac3128000)
    libutil.so.1 =&gt; /lib64/libutil.so.1 (0x00007f9ac2f25000)
    libm.so.6 =&gt; /lib64/libm.so.6 (0x00007f9ac2ca1000)
    libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f9ac294b000)
    /lib64/ld-linux-x86-64.so.2 (0x000000323e400000)
</code></pre>

<p>Looks good.  Second, how big is the shared library it created?</p>

<pre><code>xof@blog mod_wsgi-2.6]$ ls -l /usr/lib64/httpd/modules/mod_wsgi.so
-rwxr-xr-x 1 root root 339625 Oct 17 23:02 /usr/lib64/httpd/modules/mod_wsgi.so
</code></pre>

<p>We&#8217;re looking for a size in the 332 kilobyte or smaller range, to confirm that it linked against the Python library as a shared, not static, library; for a discussion of this issue, see the <a href="http://code.google.com/p/modwsgi/wiki/InstallationIssues">&#8220;Lack of Shared Library&#8221;</a> heading in the installation instructions.</p>

<p>In the next part, we&#8217;ll configure Apache, install Django, and bring up a test application.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-3-installing-apache-python-2-6-psycopg2-and-mod_wsgi/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WordPress to Django+PostgreSQL: Part 2, Configuring PostgreSQL</title>
		<link>http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-2-configuring-postgresql/</link>
		<comments>http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-2-configuring-postgresql/#comments</comments>
		<pubDate>Sat, 17 Oct 2009 17:00:13 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=86</guid>
		<description><![CDATA[<a href="http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-part-1-installing-postgresql/">In part 1</a>, we installed PostgreSQL on the VPS.  In this part, it's time to get the database server up and configured.]]></description>
			<content:encoded><![CDATA[<p><a href="http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-part-1-installing-postgresql/">In part 1</a>, we installed PostgreSQL on the VPS.  In this part, it&#8217;s time to get the database server up and configured.
<span id="more-86"></span>
First, though, now that we have something to lose on the server, backups are now enabled at Slicehost.  $5/month is cheap insurance.  This also means we can take a snapshot of the slice, which we&#8217;ll do at the end of each major checkpoint, so we can roll back to it if something gets screwed up.  (As they say in videogaming, &#8220;Hope you saved.&#8221;)</p>

<p>Since we built PostgreSQL from the tarball, rather than using an RPM, we didn&#8217;t get some of the conveniences that the RPM provides, like creating the user that the server will run as.  So let&#8217;s do that!</p>

<pre><code>[xof@blog ~]$ sudo /usr/sbin/adduser postgres
[xof@blog ~]$ sudo passwd postgres
Changing password for user postgres.
New UNIX password: 
Retype new UNIX password: 
passwd: all authentication tokens updated successfully.
</code></pre>

<p>Logging in as our shiny new user, we add the PostgreSQL binaries to our <code>$PATH</code> in the <code>.bash_profile</code>:</p>

<pre><code>PATH=$PATH:/usr/local/pgsql/bin:$HOME/bin
</code></pre>

<p>Well, no time like the present&#8230; let&#8217;s create a cluster:</p>

<pre><code>[postgres@blog ~]$ initdb db
</code></pre>

<p>We want the locale and encoding to be UTF8, and that happens to be the default:</p>

<pre><code>The database cluster will be initialized with locale en_US.UTF-8.
The default database encoding has accordingly been set to UTF8.
The default text search configuration will be set to "english".
</code></pre>

<p><em>Nota bene</em> that the default authentication is &#8220;trust&#8221;:</p>

<pre><code>WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the -A option the
next time you run initdb.
</code></pre>

<p>That&#8217;s fine for now (we&#8217;ll change it later).  As a <a href="http://en.wikipedia.org/wiki/Smoke_testing">smoke test</a>, let&#8217;s start up the server and make sure all is well:</p>

<pre><code>[postgres@blog ~]$ pg_ctl -D ~postgres/db -l logfile start
</code></pre>

<p>We&#8217;re just writing the log to a file &#8216;logfile&#8217; in the postgres user&#8217;s home director, which is not particularly sophisticated log file management. (That&#8217;s also something we&#8217;ll fix later.)</p>

<p>So, did it work?</p>

<pre><code>[postgres@blog ~]$ psql postgres
psql (8.4.1)
Type "help" for help.

postgres=#
</code></pre>

<p>Looks good!</p>

<p>Now, before we start creating new databases, let&#8217;s set up a couple of useful defaults.</p>

<pre><code>[postgres@blog ~]$ psql template1
psql (8.4.1)
Type "help" for help.

template1=# 
</code></pre>

<p>We&#8217;ll be using <a href="http://www.postgresql.org/docs/8.4/interactive/plpgsql.html">PL/pgSQL</a> functions in the future, so let&#8217;s add that language to <code>template1</code>.  The <code>template1</code> database is <a href="http://www.postgresql.org/docs/8.4/interactive/manage-ag-templatedbs.html">the template from which new databases are created</a>, so changes here will be propagated to all new databses we create in the future.</p>

<pre><code>template1=# CREATE LANGUAGE plpgsql;
CREATE LANGUAGE
</code></pre>

<p>We can also add the <a href="http://www.postgresql.org/docs/8.4/interactive/uuid-ossp.html">UUID-OSSP</a> functions:</p>

<pre><code>template1=# \i /usr/local/pgsql/share/contrib/uuid-ossp.sql
SET
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
CREATE FUNCTION
</code></pre>

<p>Great.  PostgreSQL has a ton more configuration options, of course, but this will get us started.</p>

<p>One of the other things that you don&#8217;t get when you build PostgreSQL from a tarball is an automatic <code>init.d</code> script so that PostgreSQL starts on system boot.  Fortunately, the source tarball comes packaged with a suitable startup script:</p>

<pre><code>[xof@blog ~]$ cd builds/postgresql-8.4.1/contrib/start-scripts
[xof@blog start-scripts]$ sudo cp linux /etc/rc.d/init.d/postgresql
[xof@blog start-scripts]$ sudo chmod +x /etc/rc.d/init.d/postgresql
</code></pre>

<p>The standard script doesn&#8217;t have the right location for the database directory, so we have to edit the appropriate line:</p>

<pre><code># Data directory
PGDATA="/home/postgres/db"
</code></pre>

<p>and use chkconfig to add the appropriate symlinks:</p>

<pre><code>[xof@blog start-scripts]$ sudo /sbin/chkconfig --add postgresql
</code></pre>

<p>(We went back to the <code>xof</code> account because the <code>postgres</code> account isn&#8217;t a member of <code>wheel</code>, and can&#8217;t use <code>sudo</code>, which is just the way it should be.)</p>

<p>So, did that work?  Let&#8217;s find out!</p>

<pre><code>[xof@blog ~]$ sudo reboot
</code></pre>

<p>(wait wait wait.)  Back up!</p>

<pre><code>[postgres@blog ~]$ psql postgres
psql (8.4.1)
Type "help" for help.

postgres=# 
</code></pre>

<p>Great. Note that the server logs are now being written to the default for the <code>init.d</code> file, which is <code>$PGDATA/serverlogs</code> rather than <code>~/logfile</code> as before.</p>

<p>Next, in part 3, we&#8217;ll <a href="http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-3-installing-apache-python-2-6-psycopg2-and-mod_wsgi/">install Python 2.6, Apache, <code>mod_wsgi</code> and <code>psycopg2</code></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/17/wordpress-to-djangopostgresql-part-2-configuring-postgresql/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Mighty GUCS: A guide to the essential PostgreSQL settings you need to know</title>
		<link>http://thebuild.com/blog/2009/10/16/the-mighty-gucs/</link>
		<comments>http://thebuild.com/blog/2009/10/16/the-mighty-gucs/#comments</comments>
		<pubDate>Sat, 17 Oct 2009 06:49:51 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=97</guid>
		<description><![CDATA[The archive video for the October 13, 2009 SFPUG meeting is now available:


    
    
    
    
    


For downloading, the direct link is here, and it is also available on Vimeo if that&#8217;s more your thing.

This work is licensed under [...]]]></description>
			<content:encoded><![CDATA[<p>The archive video for the October 13, 2009 SFPUG meeting is now available:
<span id="more-97"></span>
<object classid='clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b' width="640" height="496" codebase='http://www.apple.com/qtactivex/qtplugin.cab'>
    <param name='src' value="http://media.postgresql.org/sfpug/sfpug-gucs-20091013.mov">
    </param><param name='autoplay' value="false">
    </param><param name='controller' value="true">
    </param><param name='loop' value="false">
    <embed src="http://media.postgresql.org/sfpug/sfpug-gucs-20091013.mov" width="640" height="496" autoplay="false" controller="true" loop="false" bgcolor="#000000" pluginspage='http://www.apple.com/quicktime/download/'>
</embed></param></object></p>

<p>For downloading, the <a href="http://media.postgresql.org/sfpug/sfpug-gucs-20091013.mov">direct link is here</a>, and it is also <a href="http://vimeo.com/7109722">available on Vimeo</a> if that&#8217;s more your thing.</p>

<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/16/the-mighty-gucs/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
<enclosure url="http://media.postgresql.org/sfpug/sfpug-gucs-20091013.mov" length="521861125" type="video/quicktime" />
		</item>
		<item>
		<title>WordPress to Django+PostgreSQL: Part 1, Installing PostgreSQL</title>
		<link>http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-part-1-installing-postgresql/</link>
		<comments>http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-part-1-installing-postgresql/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 19:20:47 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=77</guid>
		<description><![CDATA[This is part 1 of my migration of my blog from WordPress to Django and PostgreSQL.  I&#8217;m starting with a bare Centos 5.3 slice from Slicehost, and setting it up bit by bit.

In this part, I&#8217;m installing PostgreSQL.

First, an idiosyncrasy warning: I very much prefer building PostgreSQL from source, even on package-based systems like [...]]]></description>
			<content:encoded><![CDATA[<p>This is part 1 of <a href="http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-introduction/">my migration of my blog</a> from WordPress to Django and PostgreSQL.  I&#8217;m starting with a bare Centos 5.3 slice from <a href="http://slicehost.com">Slicehost</a>, and setting it up bit by bit.</p>

<p>In this part, I&#8217;m installing PostgreSQL.
<span id="more-77"></span>
First, an idiosyncrasy warning: I very much prefer building PostgreSQL from source, even on package-based systems like Centos.  I like the extra bit of control, and knowing just what is going into my binary.</p>

<p>I&#8217;ve already created a user account (&#8217;xof&#8217;), as I much prefer to do everything through sudo (assuming root access is required) rather than logging in as root.</p>

<p>So, let&#8217;s get the development environment set up.</p>

<p>Step one, of course, is the base development tools group:</p>

<pre><code>[xof@blog ~]$ sudo yum groupinstall 'Development Tools'
</code></pre>

<p>Some of the pieces that PostgreSQL needs to build aren&#8217;t in that group, so let&#8217;s install those.</p>

<pre><code>[xof@blog ~]$ sudo yum install readline-devel
[xof@blog ~]$ sudo yum install zlib-devel
</code></pre>

<p>I&#8217;m planning to build PostgreSQL with OpenSSL support, so let&#8217;s install that as well:</p>

<pre><code>[xof@blog ~]$ sudo yum install openssl-devel
</code></pre>

<p>In addition, I&#8217;m going to be building PostgreSQL with OSSP-UUID support, so we&#8217;ll need the packages for those.  They&#8217;re not in the standard repository set, so we&#8217;ll need to find them elsewhere.  (Many thanks to Devrim Gündüz for pointing me in the right place.)</p>

<pre><code>[xof@blog ~]$ sudo rpm --install http://download.fedora.redhat.com/pub/epel/5/x86_64/uuid-1.5.1-3.el5.x86_64.rpm
[xof@blog ~]$ sudo rpm --install http://download.fedora.redhat.com/pub/epel/5/x86_64/uuid-devel-1.5.1-3.el5.x86_64.rpm
</code></pre>

<p>And now we&#8217;re ready to build!  I created a directory &#8220;builds&#8221; to hold source tarballs, and <a href="http://www.postgresql.org/download/">downloaded the PostgreSQL source</a> from the appropriate place:</p>

<pre><code>[xof@blog builds]$ tar xvfz postgresql-8.4.1.tar.gz
[xof@blog builds]$ cd postgresql-8.4.1
[xof@blog postgresql-8.4.1]$ ./configure --with-ossp-uuid --with-openssl
[xof@blog postgresql-8.4.1]$ make
</code></pre>

<p>And away it goes!  The <code>configure</code> and <code>make</code> worked cleanly on the first try.  So, time to install it:</p>

<pre><code>[xof@blog postgresql-8.4.1]$ sudo make install
</code></pre>

<p>Since I&#8217;ll be using the <code>uuid-ossp</code> contrib module, I&#8217;ll build and install that now:</p>

<pre><code>[xof@blog postgresql-8.4.1]$ cd contrib/uuid-ossp
[xof@blog uuid-ossp]$ make
[xof@blog uuid-ossp]$ sudo make install
</code></pre>

<p>For the convenience of building other things that might depend on the PostgreSQL library, I like to include the PostgreSQL libraries in <code>ldconfig</code>:</p>

<pre><code>[xof@blog ~]$ sudo sh
sh-3.2# cat &gt;&gt; /etc/ld.so.conf.d/usr-local-pgsql-lib.conf
/usr/local/pgsql/lib
sh-3.2# /sbin/ldconfig
sh-3.2# exit
[xof@blog ~]$ 
</code></pre>

<p>And PostgreSQL is installed.  In part 2, I&#8217;ll configure the database.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-part-1-installing-postgresql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WordPress to Django+PostgreSQL: Introduction</title>
		<link>http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-introduction/</link>
		<comments>http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-introduction/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 16:32:30 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=72</guid>
		<description><![CDATA[I&#8217;ve been doing a lot more development with Django and PostgreSQL lately. The logical thing to do is to blog about it, of course&#8230;

On my blog running WordPress?

Well, that won&#8217;t do at all.

So, I&#8217;m going to be migrating this blog to use Django and PostgreSQL, and will blog about the adventure here. I&#8217;ll be starting [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been doing a lot more development with <a href="http://www.djangoproject.com/">Django</a> and <a href="http://www.postgresql.org/">PostgreSQL</a> lately. The logical thing to do is to blog about it, of course&#8230;</p>

<p>On my blog running <em>WordPress</em>?</p>

<p>Well, that won&#8217;t do at all.</p>

<p>So, I&#8217;m going to be migrating this blog to use Django and PostgreSQL, and will blog about the adventure here. I&#8217;ll be starting with a bare VPS &#8220;slice&#8221; at <a href="http://www.slicehost.com/">Slicehost</a>, running Centos 5.3, and document each step.</p>

<p>Onwards to step 1: <a href="http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-part-1-installing-postgresql/">Installing PostgreSQL on the slice</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/16/wordpress-to-djangopostgresql-introduction/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Getting PostgreSQL 8.4 to only listen on Unix sockets</title>
		<link>http://thebuild.com/blog/2009/10/15/getting-postgresql-8-4-to-only-listen-on-unix-sockets/</link>
		<comments>http://thebuild.com/blog/2009/10/15/getting-postgresql-8-4-to-only-listen-on-unix-sockets/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 03:51:40 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=68</guid>
		<description><![CDATA[The default installation of PostgreSQL listens on 127.0.0.1 (the local loopback address) and on Unix sockets. The controlling parameter, listen_addresses, isn&#8217;t documented to have a setting that just listens on sockets, and not the loopback address.

As it happens, such a setting exists:

listen_addresses=''


Among other things, this appears to prevent local instances of pgAdmin from connecting (although [...]]]></description>
			<content:encoded><![CDATA[<p>The default installation of PostgreSQL listens on 127.0.0.1 (the local loopback address) and on Unix sockets. The controlling parameter, <code>listen_addresses</code>, isn&#8217;t documented to have a setting that just listens on sockets, and not the loopback address.</p>

<p>As it happens, such a setting exists:</p>

<pre><code>listen_addresses=''
</code></pre>

<p>Among other things, this appears to prevent local instances of pgAdmin from connecting (although <code>psql</code> works fine), so its utility is not clear, but there it is if you wish it.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/15/getting-postgresql-8-4-to-only-listen-on-unix-sockets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Only NATURAL: JOIN clauses vs WHERE conditions</title>
		<link>http://thebuild.com/blog/2009/10/15/only-natural-join-clauses-vs-where-conditions/</link>
		<comments>http://thebuild.com/blog/2009/10/15/only-natural-join-clauses-vs-where-conditions/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 02:52:14 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=64</guid>
		<description><![CDATA[When I learned SQL, I was taught that the way to do a join was with a WHERE clause.  For example, if you have orders:

CREATE TABLE orders (
   order_id bigserial PRIMARY KEY,
   customer_id bigint REFERENCES customers(customer_id),
   ...
)


and order lines:

CREATE TABLE order_lines (
   ordinal integer NOT NULL,
 [...]]]></description>
			<content:encoded><![CDATA[<p>When I learned SQL, I was taught that the way to do a join was with a WHERE clause.  For example, if you have orders:</p>

<pre><code>CREATE TABLE orders (
   order_id bigserial PRIMARY KEY,
   customer_id bigint REFERENCES customers(customer_id),
   ...
)
</code></pre>

<p>and order lines:</p>

<pre><code>CREATE TABLE order_lines (
   ordinal integer NOT NULL,
   order_id bigint REFERENCES orders(order_id),
   item_id bigint REFERENCES items(item_id),
   quantity decimal(10,2) NOT NULL CHECK(VALUE &gt;= 0),
   ...
   PRIMARY KEY(order_id, ordinal)
)
</code></pre>

<p>&#8230; to get a list of <code>customer_id</code>, <code>item_id</code> pairs:</p>

<pre><code>SELECT orders.customer_id, order_lines.item_id
   FROM orders, order_lines
   WHERE orders.order_id = order_lines.order_id;
</code></pre>

<p>And that works great.  However, there is another syntax, which is to use a JOIN clause in the FROM list:</p>

<pre><code>SELECT orders.customer_id, order_lines.item_id
   FROM orders NATURAL JOIN order_lines;
</code></pre>

<p>NATURAL JOIN, in the words of the <a href="http://www.postgresql.org/docs/8.4/interactive/sql-select.html#SQL-FROM">wonderful PostgreSQL documentation</a>, &#8220;is shorthand for a USING list that mentions all columns in the two tables that have the same names,&#8221; so it&#8217;s equivalent to:</p>

<pre><code>SELECT orders.customer_id, order_lines.item_id
   FROM orders JOIN order_lines USING(order_id);
</code></pre>

<p>which in turn is equivalent to:</p>

<pre><code>SELECT orders.customer_id, order_lines.item_id
   FROM orders JOIN order_lines ON orders.order_id=order_lines.order_id;
</code></pre>

<p>NATURAL JOIN is nifty, but it does have a signficant danger.  Suppose later we decided to add notes to orders:</p>

<pre><code>ALTER TABLE orders ADD COLUMN note text;
</code></pre>

<p>And to order lines, too:</p>

<pre><code>ALTER TABLE order_lines ADD COLUMN note text;
</code></pre>

<p>Suddenly, our natural join is much less, well, natural; it&#8217;s equivalent to:</p>

<pre><code>SELECT orders.customer_id, order_lines.item_id
   FROM orders JOIN order_lines ON (orders.order_id=order_lines.order_id)
      AND (orders.note=order_lines.note);
</code></pre>

<p>&#8230; which is almost certainly not what you want.  In absence of amazingly good naming discipline, NATURAL is a bit too surprising.</p>

<p>That being said, I&#8217;ve gotten very fond of USING and ON.  I find it very intuitive to separate join conditions from other filtering conditions.  For example, if we only wanted order lines with a quantity greater than zero:</p>

<pre><code>SELECT orders.customer_id, order_lines.item_id
   FROM orders JOIN order_lines USING(order_id)
   WHERE order_lines.quantity &gt; 0;
</code></pre>

<p>I like the separation of the join condition that assembles the product of the input tables from the filtration conditions, as I tend to think of those independently when designing a query.</p>

<p>This starts coming apart when you have extremely complicated join conditions, or are joining over many tables (more than three or four), it&#8217;s often clearer to move the join conditions into the WHERE clause.  Otherwise, see if separating out the join conditions from the other conditions makes your queries easier to read; it did for me.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/15/only-natural-join-clauses-vs-where-conditions/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SFPUG: Statistics and Postgres &#8212; How the Planner Sees Your Data</title>
		<link>http://thebuild.com/blog/2009/10/13/sfpug-statistics-and-postgres/</link>
		<comments>http://thebuild.com/blog/2009/10/13/sfpug-statistics-and-postgres/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 20:39:51 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=62</guid>
		<description><![CDATA[The video for the September 8, 2009 SFPUG meeting is now available:


    
    
    
    
    


For downloading, the direct link is here.

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
]]></description>
			<content:encoded><![CDATA[<p>The video for the September 8, 2009 SFPUG meeting is now available:
<span id="more-62"></span>
<object classid='clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b' width="640" height="496" codebase='http://www.apple.com/qtactivex/qtplugin.cab'>
    <param name='src' value="http://media.postgresql.org/sfpug/sfpug-statistics-20090908.mov">
    </param><param name='autoplay' value="false">
    </param><param name='controller' value="true">
    </param><param name='loop' value="false">
    <embed src="http://media.postgresql.org/sfpug/sfpug-statistics-20090908.mov" width="640" height="496" autoplay="false" controller="true" loop="false" bgcolor="#000000" pluginspage='http://www.apple.com/quicktime/download/'>
</embed></param></object></p>

<p>For downloading, the <a href="http://media.postgresql.org/sfpug/sfpug-statistics-20090908.mov">direct link is here</a>.</p>

<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/10/13/sfpug-statistics-and-postgres/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://media.postgresql.org/sfpug/sfpug-statistics-20090908.mov" length="470721843" type="video/quicktime" />
		</item>
		<item>
		<title>Quote of the Day</title>
		<link>http://thebuild.com/blog/2009/08/27/quote-of-the-day-3/</link>
		<comments>http://thebuild.com/blog/2009/08/27/quote-of-the-day-3/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 15:36:51 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=60</guid>
		<description><![CDATA[
  &#8220;The locking on this application is not so much pessimistic as clinically depressed.&#8221; &#8212; me

]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>&#8220;The locking on this application is not so much pessimistic as clinically depressed.&#8221; &#8212; me</p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/08/27/quote-of-the-day-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quote of the Day</title>
		<link>http://thebuild.com/blog/2009/08/14/quote-of-the-day-2/</link>
		<comments>http://thebuild.com/blog/2009/08/14/quote-of-the-day-2/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 23:23:37 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=55</guid>
		<description><![CDATA[
  &#8220;Hovercraft are just as happy hovering over the surface of land as of water. The authorities forbid their use on roads. And when you appreciate that they have no brakes, tend to slither off the camber down into the gutter and are deflected sideways by the slightest breeze, you can see that the [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>&#8220;Hovercraft are just as happy hovering over the surface of land as of water. The authorities forbid their use on roads. And when you appreciate that they have no brakes, tend to slither off the camber down into the gutter and are deflected sideways by the slightest breeze, you can see that the authorities have made a wise move for once.&#8221; &mdash; Chris Roper of the <a href="http://steamboatwilly.org/">Steam Boat Willy project</a>, dedicated to developing a human-powered hovercraft</p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/08/14/quote-of-the-day-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SFPUG: Windowing and Common Table Expressions</title>
		<link>http://thebuild.com/blog/2009/08/13/sfpug-windowing-and-common-table-expressions/</link>
		<comments>http://thebuild.com/blog/2009/08/13/sfpug-windowing-and-common-table-expressions/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 05:22:33 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=53</guid>
		<description><![CDATA[The video for the August 11, 2009 SFPUG meeting is now available:


    
    
    
    
    


For downloading, the direct link is here.

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
]]></description>
			<content:encoded><![CDATA[<p>The video for the August 11, 2009 SFPUG meeting is now available:
<span id="more-53"></span>
<object classid='clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b' width="640" height="496" codebase='http://www.apple.com/qtactivex/qtplugin.cab'>
    <param name='src' value="http://media.postgresql.org/sfpug/sfpug-window-20090811.mov">
    </param><param name='autoplay' value="false">
    </param><param name='controller' value="true">
    </param><param name='loop' value="false">
    <embed src="http://media.postgresql.org/sfpug/sfpug-window-20090811.mov" width="640" height="496" autoplay="false" controller="true" loop="false" bgcolor="#000000" pluginspage='http://www.apple.com/quicktime/download/'>
</embed></param></object></p>

<p>For downloading, the <a href="http://media.postgresql.org/sfpug/sfpug-window-20090811.mov">direct link is here</a>.</p>

<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/us/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/08/13/sfpug-windowing-and-common-table-expressions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://media.postgresql.org/sfpug/sfpug-window-20090811.mov" length="333931520" type="video/quicktime" />
		</item>
		<item>
		<title>Quote of the Day</title>
		<link>http://thebuild.com/blog/2009/08/10/quote-of-the-day/</link>
		<comments>http://thebuild.com/blog/2009/08/10/quote-of-the-day/#comments</comments>
		<pubDate>Tue, 11 Aug 2009 05:43:33 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=51</guid>
		<description><![CDATA[
  &#8220;The question of whether a machine can think is no more interesting than the question of whether or not a submarine can swim.&#8221; &#8212; Edsger Dijkstra

]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>&#8220;The question of whether a machine can think is no more interesting than the question of whether or not a submarine can swim.&#8221; &#8212; <a href="http://en.wikipedia.org/wiki/Edsger_W._Dijkstra">Edsger Dijkstra</a></p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/08/10/quote-of-the-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resume Building</title>
		<link>http://thebuild.com/blog/2009/08/09/resume-building/</link>
		<comments>http://thebuild.com/blog/2009/08/09/resume-building/#comments</comments>
		<pubDate>Sun, 09 Aug 2009 08:51:01 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=45</guid>
		<description><![CDATA[The trailer for the sequel to Tron looks awesome.

And this gives me an opportunity to vent one of my pet peeves about the original Tron.

In Tron, you have (in essence) a battle between three programmers: Flynn (hero), Bradley (hero), and Dillinger (villain). Now, what actual programs have these three delivered, per the movie?


Flynn: Some games [...]]]></description>
			<content:encoded><![CDATA[<p>The trailer for the sequel to <a href="http://www.flynnlives.com/media/video/0xendgame.aspx">Tron</a> looks awesome.</p>

<p>And this gives me an opportunity to vent one of my pet peeves about the original <em>Tron</em>.</p>

<p>In Tron, you have (in essence) a battle between three programmers: Flynn (hero), Bradley (hero), and Dillinger (villain). Now, what actual programs have these three delivered, per the movie?</p>

<ol>
<li>Flynn: Some games (and those he wrote after hours on the company&#8217;s computer).</li>
<li>Bradley: A pretty bad-ass security program.</li>
<li>Dillinger: An operating system which <em>becomes sentient</em>.</li>
</ol>

<p>Unsporting though it may be of me, I know which one I&#8217;d hire. With appropriate code reviews, of course.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/08/09/resume-building/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dot Dot Dot</title>
		<link>http://thebuild.com/blog/2009/08/08/dot-dot-dot/</link>
		<comments>http://thebuild.com/blog/2009/08/08/dot-dot-dot/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 23:59:23 +0000</pubDate>
		<dc:creator>Xof</dc:creator>
				<category><![CDATA[Language Issues]]></category>

		<guid isPermaLink="false">http://thebuild.com/blog/?p=39</guid>
		<description><![CDATA[In a thoughtful post at the Big Nerd Ranch blog, Joe Conway talks about the relatively new dot notation in Objective-C for invoking messages on objects.

The executive summary is, he doesn&#8217;t like it.

He&#8217;s making two arguments against dot notation:


While it is now legal Objective-C, it&#8217;s an uneasy fit to an enormous history of Objective-C code, [...]]]></description>
			<content:encoded><![CDATA[<p>In a thoughtful post at the <a href="http://weblog.bignerdranch.com/?p=83">Big Nerd Ranch blog</a>, Joe Conway talks about the relatively new dot notation in Objective-C for invoking messages on objects.</p>

<p>The executive summary is, he doesn&#8217;t like it.</p>

<p>He&#8217;s making two arguments against dot notation:</p>

<ol>
<li>While it is now legal Objective-C, it&#8217;s an uneasy fit to an enormous history of Objective-C code, and existing coding patterns in the language.</li>
<li>It blurs the lines between accessing fields in a structure and invoking code, and that&#8217;s bad in and of itself.</li>
</ol>

<p>I have no argument at all with point 1.  I personally dislike the brackets notation, but that&#8217;s just years of writing C++.  Objective-C is a different language, different syntax, get over it, write some code: no problem.</p>

<p>Point 2&#8230; well.  Maybe this is also my years of C++, but I really don&#8217;t see the problem.  For example, he writes:</p>

<blockquote>
  <p>In Objective-C, the square brackets ([]) were added for message sending. While the square brackets had previously only been used for indexing an array, the intent of the brackets can be easily determined by the context.</p>
</blockquote>

<p>That&#8217;s true, but the original reason that Objective-C used brackets was not to differentiate message sending from structure access; it was because Objective-C was (and largely still is) a preprocessor on C, and using brackets in that way made it easy to parse and do the substitutions. I&#8217;m entirely in favor of making a virtue of that necessity, but let&#8217;s not forget that the original reason was arbitrary, and unique in the history of object-oriented extensions to C.</p>

<p>He goes on to say, in the example:</p>

<pre><code>int x = foo.value;
</code></pre>

<blockquote>
  <p>What does that mean? Are we getting the value field out of the structure object foo? Are we executing a simple method that returns a value? Or, in this case, are we creating a network connection, pulling a value from a web server, turning that data in to an integer and then returning it?</p>
</blockquote>

<p>Well, yes, but we really don&#8217;t any more in:</p>

<pre><code>int x = [foo value];
</code></pre>

<p>except that we&#8217;re running some code. He writes:</p>

<blockquote>
  <p>Our first glance tells us we are definitely sending a message. That clues us in that more work is being done, not just a simple memory offset and an assignment.</p>
</blockquote>

<p>OK, good, we do know that we&#8217;re sending a message, but&#8230; well, we still don&#8217;t know anything at all about the nature of the message than we did in the first example. Calling these things &#8220;foo&#8221; and &#8220;value&#8221; is stacking the deck a bit, too; if the example was either:</p>

<pre><code>int remoteMemoryTotal = remoteConnectionPartner.getRemoteMemoryUse;
</code></pre>

<p>or</p>

<pre><code>int remoteMemoryTotal = [remoteConnectionPartner getRemoteMemoryUse];
</code></pre>

<p>it&#8217;s a bit harder to argue that we have zero information about what&#8217;s going on.</p>

<p>My preference for dot notation largely comes from the desire for encapsulation. I like the idea that if I need to swap out an implementation detail, I can do so without a syntax change. For me, the fact that accessing a field off of an object, and invoking a method on that object use the same syntax is a feature, not a bug.</p>

<p>Part of it is cultural, I suspect. Objective-C is an interesting hybrid language. The object model is very dynamic and fluid, very Smalltalk-y, but that&#8217;s added on top of C. Not a &#8220;C-like language,&#8221; but C. K&amp;R C. Thus, there&#8217;s a huge difference (in philosophy as well as performance) between reading an int out of a structure and sending a message to an object that returns an int, and the syntax reflects that. In other languages, like C++ and Java, the philosophical difference is reduced (somewhat in C++, greatly in Java), and a founding principle of those languages was to make &#8220;get something from an object&#8221; be the fundamental operation.</p>

<p>He does make some good points about returning l-values from functions (something that C++ wrestled with unhappily), which is a requirement for writing really nice setters as well as gettings using dot notation. All in all, I agree with his fundamental point that:</p>

<blockquote>
  <p>You aren’t at home. You’re working with another language.</p>
</blockquote>

<p>&#8230; even if I don&#8217;t accept the premise that using dot notation to invoke methods is fundamentally a bad idea.</p>
]]></content:encoded>
			<wfw:commentRss>http://thebuild.com/blog/2009/08/08/dot-dot-dot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
