<?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>Musings of an Anonymous Geek &#187; Database</title>
	<atom:link href="http://www.protocolostomy.com/category/database/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.protocolostomy.com</link>
	<description>Made with only the finest 1's and 0's</description>
	<lastBuildDate>Thu, 03 Nov 2011 04:08:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>PyTPMOTW: PsycoPG2</title>
		<link>http://www.protocolostomy.com/2010/04/21/pytpmotw-psycopg2/</link>
		<comments>http://www.protocolostomy.com/2010/04/21/pytpmotw-psycopg2/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 01:29:56 +0000</pubDate>
		<dc:creator>bkjones</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[PyTPMOTW]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=761</guid>
		<description><![CDATA[What is this module for? Interacting with a PostgreSQL database in Python. What is PostgreSQL? PostgreSQL is an open source relational database product. It has some more advanced features, like built-in networking-related and GIS-related datatypes, the ability to script stored functions in multiple languages (including Python), etc. If you have never heard of PostgreSQL, get [...]]]></description>
			<content:encoded><![CDATA[<h3>What is this module for?</h3>
<p>Interacting with a PostgreSQL database in Python.</p>
<h3>What is PostgreSQL?</h3>
<p>PostgreSQL is an open source relational database product. It has some more advanced features, like built-in networking-related and GIS-related datatypes, the ability to script stored functions in multiple languages (including Python), etc. If you have never heard of PostgreSQL, get out from under your rock!</p>
<h3>Making Contact</h3>
<p>Using the pscyopg2 module to connect to a PostgreSQL database couldn&#8217;t be simpler. You can use the connect() method of the module, passing in either the individual arguments required to make contact (dbname, user, etc), or you can pass them in as one long &#8220;DSN&#8221; string, like this:</p>
<pre class="brush: python; title: ; notranslate">
dsn = &quot;host=localhost port=6000 dbname=testdb user=jonesy&quot;
conn = psycopg2.connect(dsn)
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
</pre>
<p>The DSN value is a space-delimited collection of key=value pairs, which I construct before sending the dsn to the psycopg2.connect() method. Once we have a connection object, the very first thing I do is set the connection&#8217;s isolation level to &#8216;autocommit&#8217;, so that INSERT and UPDATE transactions are committed automatically without my having to call conn.commit() after each transaction. There are several isolation levels defined in the psycopg2.extensions package, and they&#8217;re defined in &#8216;extensions&#8217; because they go beyond what is defined in the DB API 2.0 spec that is typically used as a reference in creating Python database modules.</p>
<h3>Simple Queries and Type Conversion</h3>
<p>In order to get anything out of the database, we have to know how to talk to it. Of course this means writing some SQL, but it also means sending query arguments in a format understood by the database. I&#8217;m happy to report that psycopg2 does a pretty good job of making things &#8220;just work&#8221; when it comes to converting your input into PostgreSQL types, and converting the output directly into Python types for easy manipulation in your code. That said, understanding how to properly use these features can be a bit confusing at first, so let me address the source of a lot of early confusion right away:</p>
<pre class="brush: python; title: ; notranslate">
cur = conn.cursor()
cur.execute(&quot;&quot;&quot;SELECT id, fname, lname, balance FROM accounts WHERE balance &gt; %s&quot;&quot;&quot;, min_balance)
</pre>
<p>Chances are, min_balance is an integer, but we&#8217;re using &#8216;%s&#8217; anyway. Why? Because this isn&#8217;t really you telling Python to do a string formatting operation, it&#8217;s you telling psycopg2 to convert the incoming data using the default psycopg2 method, which converts integers into the PostgreSQL INT type. So, you can use &#8220;%s&#8221; in the &#8216;execute()&#8217; method to properly convert integers, strings, dates, datetimes, timedeltas, lists, tuples and most other native Python types to a corresponding PostgreSQL type. There are adapters built into psycopg2 as well if you need more control over the type conversion process.</p>
<h3>Cursors</h3>
<p>Psycopg2 makes it pretty easy to get your results back in a format that is easy for the receiving code to deal with. For example, the projects I work on tend to use the  RealDictCursor type, because the code tends to require accessing the parts of the resultset rows by name rather than by index (or just via blind looping). Here&#8217;s how to set up and use a RealDictCursor:</p>
<pre class="brush: python; title: ; notranslate">
curs = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
curs.execute(&quot;SELECT id, name FROM users&quot;)
rs = curs.fetchall()
for row in rs:
   print rs['id'], rs['name']
</pre>
<p>It&#8217;s possible you have two sections of code that&#8217;ll rip apart a result set, and one needs by-name access, and the other just wants to loop blindly or access by index number. If that&#8217;s the case, just replace &#8216;RealDictCursor&#8217; with &#8216;DictCursor&#8217;, and you can have it both ways!</p>
<p>Another nice thing about psycopg2 is the cursor.query attribute and cursor.mogrify method. Mogrify allows you to test and see how a query will look after all input variables are bound, but before the query is sent to the server. Cursor.query prints out the exact query that was actually sent over the wire. I use cursor.query in my logging output all the time to catch out-of-order parameters and mismatched input types, etc. Here&#8217;s an example:</p>
<pre class="brush: python; title: ; notranslate">
try:
    curs.callproc('myschema.myprocedure', callproc_params)
except Exception as out:
    print out
    print curs.query
</pre>
<h3>Calling Stored Functions</h3>
<p>Stored procedures or &#8216;functions&#8217; in PostgreSQL-speak can be immensely useful in large complex applications where you want to enforce business rules in a single place outside the domain of the main application developers. It can also in some cases be more efficient to put functionality in the database than in the main application code. In addition, if you&#8217;re hiring developers, they should develop in the standard language for your environment, not SQL: SQL should be written by database administrators and developers, and exposed to the developers as needed, so all the developers have to do is call this newly-exposed function. Here&#8217;s how to call a function using psycopg2:</p>
<pre class="brush: python; title: ; notranslate">
callproc_params = [uname, fname, lname, uid]
cur.callproc(&quot;myschema.myproc&quot;, callproc_params)
</pre>
<p>The first argument to &#8216;callproc()&#8217; is the name of the stored procedure, and the second argument is a sequence holding the input parameters to the function. The input parameters should be in the order that the stored procedure expects them, and I&#8217;ve found after quite a bit of usage that the module typically is able to convert the types perfectly well without my intervention, with one exception&#8230;</p>
<h3>The UUID Array</h3>
<p>PostgreSQL has built-in support for lots of interesting data types, like INET types for supporting IP addresses and CIDR network blocks, and GIS-related data types. In addition, PostgreSQL supports a type that is an array of UUIDs. This comes in handy if you use a UUID to identify items and want to store an array of them to associate with an order, or you use UUIDs to track messages and want to store an array of them together to represent a message thread or conversation. To get a UUID array into the database quickly and easily, it&#8217;s really not too difficult. If you have a list of strings that are UUID strings, you can do a quick conversion, call one function, and then use the array like any other input parameter:</p>
<pre class="brush: python; title: ; notranslate">
my_uuid_arr = [uuid.UUID(i) for i in my_uuid_arr]
psycopg2.extras.register_uuid()
callproc_params = [
myvar1,
myvar2,
my_uuid_arr
]

curs.callproc('myschema.myproc', callproc_params)
</pre>
<h3>Connection Status</h3>
<p>It&#8217;s not a given that your database connection lives on from query to query, and you shouldn&#8217;t really just assume that because you did a query a fraction of a second ago that it&#8217;s still around now. Actually, to speak about things more Pythonically, you *should* assume the connection is still there, but be ready for failure, and check the connection status to diagnose and help get things back on track. You can check the &#8216;status&#8217; attribute of your connection object. Here&#8217;s one way you might do it:</p>
<pre class="brush: python; title: ; notranslate">
    @property
    def active_dbconn(self):
        return self.conn.status in [psycopg2.extensions.STATUS_READY, psycopg2.extensions.STATUS_BEGIN]:
</pre>
<p>So, I&#8217;m assuming here that you have some object that has a connection object that it refers to as &#8216;self.connection&#8217;. This one-liner function uses the @property built-in Python decorator, so the other methods in the class can either check the connection status before attempting a query:</p>
<pre class="brush: python; title: ; notranslate">
if self.active_dbconn:
    try:
        curs.execute(...)
    except Exception as out:
         logging.error(&quot;Houston we have a problem&quot;)
</pre>
<p>Or you can flip that around like this:</p>
<pre class="brush: python; title: ; notranslate">
try:
   curs.execute(...)
except Exception as out:
    if not self.active_dbconn:
        logging.error(&quot;Execution failed because your connection is dead&quot;)
    else:
         logging.error(&quot;Execution failed in spite of live connection: %s&quot; % out)
</pre>
<h3>Read On&#8230;</h3>
<p>A database is a large, complex beast. There&#8217;s no way to cover the entirety of a database or a module that talks to it in a simple blog post, but I hope I&#8217;ve been able to show some of the more common features, and maybe one or two other items of interest. If you want to know more, I&#8217;m happy to report that, after a LONG time of being unmaintained, the project has recently sprung back to life and is pretty well-documented these days. <a href="http://initd.org/psycopg/docs/index.html">Check it out! </a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2010/04/21/pytpmotw-psycopg2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python, PostgreSQL, and psycopg2&#8242;s Dusty Corners</title>
		<link>http://www.protocolostomy.com/2009/12/01/python-postgresql-and-psycopg2s-dusty-corners/</link>
		<comments>http://www.protocolostomy.com/2009/12/01/python-postgresql-and-psycopg2s-dusty-corners/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 03:07:59 +0000</pubDate>
		<dc:creator>bkjones</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=655</guid>
		<description><![CDATA[Last time I wrote code with psycopg2 was around 2006, but I was reacquainted with it over the past couple of weeks, and I wanted to make some notes on a couple of features that are not well documented, imho. Portions of this post have been snipped from mailing list threads I was involved in. [...]]]></description>
			<content:encoded><![CDATA[<p>Last time I wrote code with psycopg2 was around 2006, but I was reacquainted with it over the past couple of weeks, and I wanted to make some notes on a couple of features that are not well documented, imho. Portions of this post have been snipped from mailing list threads I was involved in.</p>
<h3>Calling PostgreSQL Functions with psycopg2</h3>
<p>So you need to call a function. Me too. I had to call a function called &#8216;myapp.new_user&#8217;. It expects a bunch of input arguments. Here&#8217;s my first shot after misreading some piece of some example code somewhere:</p>
<pre class="brush: python; title: ; notranslate">
qdict = {'fname': self.fname, 'lname': self.lname, 'dob': self.dob, 'city': self.city, 'state': self.state, 'zip': self.zipcode}

sqlcall = &quot;&quot;&quot;SELECT * FROM myapp.new_user( %(fname)s, %(lname)s,
%(dob)s, %(city)s, %(state)s, %(zip)s&quot;&quot;&quot; % qdict

curs.execute(sqlcall)
</pre>
<p>There&#8217;s no reason this should work, or that anyone should expect it to work. I just wanted to include it in case someone else made the same mistake. Sure, the proper arguments are put in their proper places in &#8216;sqlcall&#8217;, but they&#8217;re not quoted at all.</p>
<p>Of course, I foolishly tried going back and putting quotes around all of those named string formatting arguments, and of course that fails when you have something like a quoted &#8220;NULL&#8221; trying to move into a date column. It has other issues too, like being error-prone and a PITA, but hey, it was pre-coffee time.</p>
<p>What&#8217;s needed is a solution whereby psycopg2 takes care of the formatting for us, so that strings become strings, NULLs are passed in a way that PostgreSQL recognizes them, dates are passed in the proper format, and all that jazz.</p>
<p>My next attempt looked like this:</p>
<pre class="brush: python; title: ; notranslate">
curs.execute(&quot;&quot;&quot;SELECT * FROM myapp.new_user( %(fname)s, %(lname)s,
%(dob)s, %(city)s, %(state)s, %(zip)s&quot;&quot;&quot;, qdict)
</pre>
<p>This is, according to some articles, blog posts, and at least one reply on the psycopg mailing list &#8220;the right way&#8221; to call a function using psycopg2 with PostgreSQL. I&#8217;m here to tell you that this is not correct to the best of my knowledge.The only real difference between this attempt and the last is I&#8217;ve replaced the &#8220;%&#8221; with a comma, which turns what *was* a string formatting operation into a proper SELECT with a psycopg2-recognized parameter list. I thought this would get psycopg2 to &#8220;just work&#8221;, but no such luck. I still had some quoting issues.</p>
<p>I have no idea where I read this little tidbit about psycopg2 being able to convert between Python and PostgreSQL data types, but I did. Right around the same time I was thinking &#8220;it&#8217;s goofy to issue a SELECT to call a function that doesn&#8217;t really want to SELECT anything. Can&#8217;t callproc() do this?&#8221; Turns out callproc() is really the right way to do this (where &#8220;right&#8221; is defined by the DB-API which is the spec for writing a Python database module). Also turns out that psycopg2 can and will do the type conversions. Properly, even (in my experience so far).</p>
<p>So here&#8217;s what I got to work:</p>
<pre class="brush: python; title: ; notranslate">
callproc_params = [self.fname, self.lname, self.dob, self.city, self.state, self.zipcode]

curs.callproc('myapp.new_user', callproc_params)
</pre>
<p>This is great! Zero manual quoting or string formatting at all! And no &#8220;SELECT&#8221;. Just call the procedure and pass the parameters. The only thing I had to change in my code was to make my &#8216;self.dob&#8217; into a datetime.date() object, but that&#8217;s super easy, and after that psycopg2 takes care of the type conversion from a Python date to a PostgreSQL date. Tomorrow I&#8217;m actually going to try calling callproc() with a list object inside the second argument. Wish me luck!</p>
<h3>A quick cursor gotcha</h3>
<p>I made a really goofy mistake. At the root of it, what I did was share a connection *and a cursor object* among all methods of a class I created to abstract database operations out of my code. So, I did something like this (this is not the exact code, and it&#8217;s untested. Treat it like pseudocode):</p>
<pre class="brush: python; title: ; notranslate">
class MyData(object):
   def __init__(self, dsn):
      self.conn = psycopg2.Connection(dsn)
      self.cursor = self.conn.cursor()

   def get_users_by_regdate(self, regdate, limit):
      self.cursor.arraysize = limit
      self.cursor.callproc('myapp.uid_by_regdate', regdate)
      while True:
         result = self.cursor.fetchmany()
         if not result:
            break
         yield result

   def user_is_subscribed(self, uid):
      self.cursor.callproc('myapp.uid_subscribed', uid)
      result = self.cursor.fetchone()
      val = result[0]
      return val
</pre>
<p>Now, in the code that uses this class, I want to grab all of the users registered on a given date, and see if they&#8217;re subscribed to, say, a mailing list, an RSS feed, a service, or whatever. See if you can predict the issue I had when I executed this: </p>
<pre class="brush: python; title: ; notranslate">
    db = MyData(dsn)
    for id in db.get_users_by_regdate([joindate]):
        idcount += 1
        print idcount
        param = [id]
        if db.user_is_subscribed(param):
            print &quot;User subscribed&quot;
            skip_count += 1
            continue
        else:
            print &quot;Not good&quot;
            continue
</pre>
<p>Note that the above is test code. I don&#8217;t actually want to continue to the top of the loop regardless of what happens in production <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </p>
<p>So what I found happening is that, if I just commented out the portion of the code that makes a database call *inside* the for loop, I could print &#8216;idcount&#8217; all the way up to thousands of results (however many results there were). But if I left it in, only 100 results made it to &#8216;db.user_is_subscribed&#8217;. </p>
<p>Hey, &#8217;100&#8242; is what I&#8217;d set the curs.arraysize() to! Hey, I&#8217;m using the *same cursor* to make both calls! And with the for loop, the cursor is being called upon to produce one recordset while it&#8217;s still trying to produce the first recordset! </p>
<p>Tom Roberts, on the psycopg list, states the issue concisely: </p>
<blockquote><p>The cursor is stateful; it only contains information about the last<br />
query that was executed.  On your first call to &#8220;fetchmany&#8221;, you fetch a<br />
block of results from the original query, and cache them.  Then,<br />
db.user_is_subscribed calls &#8220;execute&#8221; again.  The cursor now throws away all<br />
of the information about your first query, and fetches a new set of<br />
results.  Presumably, user_is_subscribed then consumes that dataset and<br />
returns.  Now, the cursor is position at end of results.  The rows you<br />
cached get returned by your iterator, then you call fetchmany again, but<br />
there&#8217;s nothing left to fetch&#8230;</p>
<p>&#8230;So, the lesson is if you need a new recordset, you create a new cursor.</p></blockquote>
<p>Lesson learned. I still think it&#8217;d be nice if psycopg2 had more/better docs, though. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2009/12/01/python-postgresql-and-psycopg2s-dusty-corners/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>New Job, Car, Baby, and Other News</title>
		<link>http://www.protocolostomy.com/2009/10/22/new-job-car-baby-and-other-news/</link>
		<comments>http://www.protocolostomy.com/2009/10/22/new-job-car-baby-and-other-news/#comments</comments>
		<pubDate>Fri, 23 Oct 2009 02:02:48 +0000</pubDate>
		<dc:creator>bkjones</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[LinuxLaboratory]]></category>
		<category><![CDATA[Other Cool Blogs]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=631</guid>
		<description><![CDATA[New Baby! I know this is my geek blog, but geeks have kids too, so first I want to announce the birth of our second daughter, Sadie, who was born on September 15th. She&#8217;s now over a month old. This is the first time I&#8217;ve stayed up late enough to blog about her. Everyone is [...]]]></description>
			<content:encoded><![CDATA[<h3>New Baby!</h3>
<p>I know this is my geek blog, but geeks have kids too, so first I want to announce the birth of our second daughter, Sadie, who was born on September 15th. She&#8217;s now over a month old. This is the first time I&#8217;ve stayed up late enough to blog about her. Everyone is healthy, if slightly sleep-deprived <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>New Job!</h3>
<p>The day before Sadie&#8217;s birth, I got a call with an offer for a job. A *full-time* job, as a Senior Operations Developer for <a href="http://myyearbook.com">MyYearbook.com</a>. After learning about the cool and very geeky things going on at MyYearbook during the interview process, I couldn&#8217;t turn it down. I started on October 5, and it&#8217;s been a blast digging into all of the cool stuff going on there. While I&#8217;m certainly doing my fair share of PHP code review, maintenance, and general coding, I&#8217;m also getting plenty of hours in working out the Python side of my brain. I&#8217;m finding that while it&#8217;s easier switching gears than I had anticipated, I do make some really funny minor syntax errors, like using dot notation to access object attributes in PHP ;-P</p>
<p>What I find super exciting is something that might turn some peoples&#8217; stomachs: at the end of my first week, I sat back and looked at my monitors to find roughly 15 tabs in Firefox open to pages explaining various tools I&#8217;d never gotten to use, protocols I&#8217;ve never heard of, etc. I had my laptop and desktop both configured with 2 virtual machines for testing and playing with new stuff. I had something north of 25 terminal windows open, and 8 files open in Komodo Edit.</p>
<p>Now THAT, THAT is FUN!</p>
<p>The projects I&#8217;m working on run the gamut from code cleanups that nobody else has had time to do (a good tool for getting my brain wrapped around various parts of the code base), to working on scalability solutions and new offerings involving my background in coding *and* system administration. It&#8217;s like someone cherry-picked a Bay Area startup and dropped it randomly 30 minutes from my house.</p>
<p>My own business is officially &#8220;not taking new clients&#8221;. I have some regular clients that I still do work for, so my &#8220;regulars&#8221; are still being served, but they&#8217;ve all been put on notice that I&#8217;m unavailable until the new year.</p>
<h3>New Car!</h3>
<p>I&#8217;m less excited about the new car, really. I used to drive a Jeep Liberty, and I loved it. However, in early September, before Sadie&#8217;s arrival, it became clear to me that putting two car seats in that beast wasn&#8217;t going to happen. The Jeep is great for drivers, and it has some cargo space. It&#8217;s not a great vehicle for passengers, though.</p>
<p>At the same time, I was running a business (this was before the job offer came along), and I was finding myself slightly uncomfortable delivering rather serious business proposals in a well-used 2003 Jeep. So, I needed something that could fit my young family (my oldest is 2 yrs), and that was presentable to clients. So, I got a Lexus ES350.</p>
<p>I like most things about the car, except for the audio system. It seems schizophrenic to me to have like 6 sound &#8216;zones&#8217; to isolate the audio to certain sets of speakers, but then controls like bass and treble only go from 0 to 5. Huh? And the sound always sounds like it&#8217;s lying on the floor for some reason. It&#8217;s not at all immersive. The sound system on my Jeep completely kicked ass. I miss it. A lot.</p>
<h3>Other News</h3>
<p>I&#8217;ve submitted an article to <a href="http://pythonmagazine.com">Python Magazine</a> about my (relatively) recent work with Django and my (temporarily stalled) overhaul of <a href="http://linuxlaboratory.org">LinuxLaboratory.org</a>, and my experiences with various learning resources related to Django. If you&#8217;re looking to get into Django, it&#8217;s probably a good read.</p>
<p>I&#8217;ve been getting into some areas of Python that were previously dark, dusty corners, so hopefully I&#8217;ll be writing more about Python here, because writing about something helps me to solidify things in my own brain. Short of that, it serves as a future reference point in case it didn&#8217;t get solidified enough <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>My sister launched<a href="http://thedancejones.com/blog"> The Dance Jones</a>, a blog where she talks about fitness, balance, dance, and stuff I should probably pay much more attention to (I&#8217;m close to declaring war on my gut). Also, if you ever wanted to know how to <a href="http://thedancejones.com/blog/2009/10/19/how-to-shoulder-shimmy/">shoulder shimmy</a> (and who hasn&#8217;t wanted to do that?), you should check it out <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2009/10/22/new-job-car-baby-and-other-news/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>LinuxLaboratory woes, Drupal -&gt; Django?</title>
		<link>http://www.protocolostomy.com/2009/07/21/linuxlaboratory-woes-drupal-django/</link>
		<comments>http://www.protocolostomy.com/2009/07/21/linuxlaboratory-woes-drupal-django/#comments</comments>
		<pubDate>Tue, 21 Jul 2009 19:33:55 +0000</pubDate>
		<dc:creator>bkjones</dc:creator>
				<category><![CDATA[Big Ideas]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Freelancing]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[LinuxLaboratory]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Services]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=556</guid>
		<description><![CDATA[Ugh&#8230; So, today I tried browsing to one of my sites, linuxlaboratory.org, and found a 403 &#8220;Forbidden&#8221; error. Calling support, they said it was a &#8220;billing issue&#8221;. Well, I pay my bills, and I haven&#8217;t received any new credit cards, so I&#8217;m not sure what that&#8217;s about. Further, they haven&#8217;t contacted me in any way [...]]]></description>
			<content:encoded><![CDATA[<h3>Ugh&#8230;</h3>
<p>So, today I tried browsing to one of my sites, linuxlaboratory.org, and found a 403 &#8220;Forbidden&#8221; error. Calling support, they said it was a &#8220;billing issue&#8221;. Well, I pay my bills, and I haven&#8217;t received any new credit cards, so I&#8217;m not sure what that&#8217;s about. Further, they haven&#8217;t contacted me in any way shape or form at all in a very long time, and I&#8217;ve had the same email addresses for years now. Last time they failed to contact me, it was because they were sending all of the mail to &#8220;root@localhost&#8221; on the web server.</p>
<p>What&#8217;s more, the tech support guy, having determined that this wasn&#8217;t a technical but an administrative problem, transferred me to a sales person who was not there. I left a message. That was 3 hours ago. So I took matters into my own hands and changed the name server records to my webfaction account, and linuxlaboratory.org now points to an old test version of the site that uses Drupal.</p>
<h3>It&#8217;s Over Between Us&#8230;</h3>
<p>Drupal holds the record for the CMS that has run LinuxLaboratory the longest. Since its launch in 2001, LinuxLaboratory has used all of the major, and some of the minor open source PHP CMSes. Drupal gave me something very close to what I wanted, out of the box. Nowadays, Drupal is even nicer since they redid some of the back end APIs and attracted theme and module developers to the project. I&#8217;ve even done some coding in Drupal myself, and have to say that it really is a breeze.</p>
<p>But the problem is this: I&#8217;m a consultant, trainer, and author/editor. I am an experienced system admin, database admin, and infrastructure architect who makes a living solving other peoples&#8217; problems. I really can&#8217;t afford to have something that is super high overhead to maintain running my sites. With Drupal releasing new versions with major security fixes once per month on average, and no automated update mechanism (and no built-in automated backup either), it becomes pretty cumbersome just to keep it updated.</p>
<p>This is in addition to my experiences trying to do e-commerce with Drupal. I tried to use one plugin, but soon found myself in dependency hell &#8212; a situation I&#8217;m not used to being in unless I&#8217;m on a command line somewhere. So, out with Drupal. I know it well and I&#8217;m sure I&#8217;ll find a use for it somewhere in my travels, but not now, and not for this.</p>
<h3>Is Django the Future of LinuxLaboratory?</h3>
<p>So I&#8217;m thinking of giving Django another shot. In fact, I thought I might try something new and interesting. Maybe I&#8217;ll build my Django app right in front of everyone, so that anyone who is interested can follow along, and so people can give me feedback and tips along the way. It also lets me share with people who have questions about a feature I&#8217;m implementing or something like that.</p>
<p>For fanboys of &lt;insert technology here&gt;, know this: I&#8217;m a technology whore. I consume technology like some people consume oxygen. I love technology, and I get on kicks, and every now and then, a &#8220;kick&#8221; turns into a more permanent part of my tool chest. Python is one such example. I&#8217;ve done lots with Python, but have never really made friends with it for web development. I got a webfaction account specifically because they support Python (and Django). I&#8217;ve done nothing with it. Now I think I might.</p>
<p>But not to worry! I own lots of domains that are sitting idle right now, and I&#8217;m considering doing a Ruby on Rails app for one of them, and I&#8217;m dying to do more with Lua. There&#8217;s only so much time!</p>
<h3>Webfaction Django Users: Advice Hereby Solicited</h3>
<p>So if you&#8217;re a webfaction customer using Django, please share your tips with me about the best way to deploy it. I&#8217;ve used nothing but PHP apps so far, and found that rather than use the one-click installs webfaction provides, it&#8217;s a lot easier to just choose the generic &#8220;CGI/PHP&#8221; app type and install the code myself. This allows me to, for example, install and update wordpress using SVN. Is Django a similar story, or does webfaction actually have an auto-upgrade mechanism for this? How are you keeping Django up to date?</p>
<p>Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2009/07/21/linuxlaboratory-woes-drupal-django/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>I&#8217;m Offering Pro-Bono Consulting</title>
		<link>http://www.protocolostomy.com/2009/07/20/im-offering-pro-bono-consulting/</link>
		<comments>http://www.protocolostomy.com/2009/07/20/im-offering-pro-bono-consulting/#comments</comments>
		<pubDate>Tue, 21 Jul 2009 04:10:38 +0000</pubDate>
		<dc:creator>bkjones</dc:creator>
				<category><![CDATA[Big Ideas]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Freelancing]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Services]]></category>

		<guid isPermaLink="false">http://www.protocolostomy.com/?p=553</guid>
		<description><![CDATA[I started my company about a year ago, but I&#8217;ve been doing consulting for a long time. In fact, my first job in the IT industry was working for a consulting firm. Before that, starting as far back as grade school, I was involved in a lot of volunteer civic and community service activities. I [...]]]></description>
			<content:encoded><![CDATA[<p>I started <a href="http://owladvisors.com">my company</a> about a year ago, but I&#8217;ve been doing consulting for a long time. In fact, my first job in the IT industry was working for a consulting firm. Before that, starting as far back as grade school, I was involved in a lot of volunteer civic and community service activities. I admire companies who get involved in their communities, or even outside of their communities, wherever help is needed.</p>
<p>As part of my business plan, I&#8217;ve put in place a policy of accepting one pro-bono consulting project per year. So far, I haven&#8217;t gotten any requests for free consulting work, so here&#8217;s my public shout out to let you know what types of services are available:</p>
<p>1. Speaking or Training. My specialties are things like advanced Linux administration and SQL, but I&#8217;m perfectly capable of delivering content for people who just need to know how the internet works, or want to know more about social media.Training, funny enough, has been the bulk of my business for the past year.</p>
<p>2. I can help with MySQL performance tuning on *nix systems, including finding hotspots related to the design of the database itself, or how your application code interacts with the database. If it happens that your MySQL server is performing poorly due to an underpowered system, I can also pinpoint which resource is dragging on the performance of your database.</p>
<p>3. If you just need random scripts written to perform *nix system administration tasks, I can consult with you about the requirements and write them for you. Note that while I can script in several languages, my preference for anything longer than 40 lines of code is Python.</p>
<p>4. I can build PC&#8217;s, install networks, set up firewalls and wireless routers, and all of the normal &#8220;office IT&#8221; functions, but note that my consulting is Linux consulting. I don&#8217;t work with Windows (well, I do, but not for free) <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>5. If there&#8217;s some other thing you&#8217;ve seen me blog about here, chances are I&#8217;ll be willing to perform a pro-bono consulting engagement to do it for you, or show you how to approach a problem, a large project, a migration, automation, monitoring, security or whatever.</p>
<p>Unless you happen to live within commuting distance to Princeton, NJ, work will be done remotely <img src='http://www.protocolostomy.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Please email your request to jonesy at owladvisors dot com. Include your organization&#8217;s name, your contact info, and as much detail about the project and what your organization does as possible. The decision of which project to take on will be based solely on the information in your request!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.protocolostomy.com/2009/07/20/im-offering-pro-bono-consulting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

