Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Wednesday, August 3, 2011

Django 1.3 model ID not showing up after .save() with PostgreSQL

So there was an interesting change with how Django selects the value for an ID with the PostgreSQL back end between 1.1 and 1.3 (or perhaps 1.2, I'm not sure.)

The function to get the ID of the newly saved model used to read:


def last_insert_id(self, cursor, table_name, pk_name):
cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name))
return cursor.fetchone()[0]


But in 1.3 (at least), it reads:


def last_insert_id(self, cursor, table_name, pk_name):
# Use pg_get_serial_sequence to get the underlying sequence name
# from the table name and column name (available since PostgreSQL 8)
cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (
self.quote_name(table_name), pk_name))
return cursor.fetchone()[0]


The difference is that 1.3 asks PostgreSQL what the name of the sequence is based on the table+pk name. The name is a little misleading as the PostgreSQL documentation indicates. It really should be like "pg_get_owned_sequence" because that's what it's asking: what is the sequence owned by this column?

It turns out if you have a pk that was created as an INTEGER and then assigned a default value of the next value of a sequence... you still don't quite have the same thing as a pk defined as serial because the column won't own the sequence.

You can rectify the situation thus:

ALTER SEQUENCE sequencename OWNED BY table.pk

And that will fix it. Then the pg_get_serial_sequence call will not return NULL, and your model will get an ID.

This is all something you can figure out with the documentation on the web, but I figured I'd put it here to maybe help someone, somewhere.

Friday, February 5, 2010

APIs are more important than code

I have spent a lot of time in my career worried about clean code. Using patterns and good naming conventions (naming things is still one of the two hard things) to produce the simplest, most elegant code possible. But in the last six months or so I've learned that it doesn't matter.

Well, it does matter but clean code's importance is dwarfed by a few things. Two of those things are API design and scope of responsibility.

No matter how beautiful your code is, if it does too much stuff it's still bad. And no matter how bad the code is, if the API is well thought out, easy to use and doesn't try to have too much responsibility ... you're OK. You can always refactor bad code.

You would think that this would have been obvious to me after I started doing TDD seriously. It wasn't. I mean, I knew API design was important and that code shouldn't do too much, but for me to really grok that API design and scope of responsibility was more important than clean code, I had to see the mistakes being made.

I had to see the far reaching problems caused by modules that did too much or projects that dipped too deeply into the responsibilities of others. The effect of unreadable, bad code is immediately visible. The effect of bad API design or creeping outside the realm of your true responsibility is much, much more insidious and can poison projects and waste a lot of time. Many of the mistakes I've seen over my career could have been prevented by asking these questions, or questions like them:

  • "What does this feature I'm adding have to do with this module I'm adding it to? Does it belong here or is it orthogonal?"
  • "Does this module I'm reimplementing/moving really have responsibility for this feature?"
  • "What information will the caller have when they need my API to do stuff?"
  • "How will the caller want to use my API?" (This should be easy to answer if you're using TDD)
Very simple, obvious questions, but for the longest time I put less emphasis on them than I did on questions like "Should I refactor this decision logic to command pattern?" or "Is this more suited to builder or factory?"

Clean code is important, I still believe. Patterns can certainly make code more elegant. Naming methods and modules is still very hard and very important. But I have re-assigned the weight I'm going to give them. This is the kind of "mental shift" that has happened several times now in my career. They usually occur when I'm transitioning in or out of a job: you readjust what you know based on new evidence or use cases. It's humbling and exciting. It's also usually obvious. (This probably happens to me more than most other programmers since I have little formal training in computer science and I'm just not very good at it.)

So, my new adventure is going to be going back to Python (and using Django this time around) as as kind of a "clean up" consultant for the non-profit my brother works for. This will be an excellent area for flexing/building API design skills since Django has really neat ways to make pluggable, reusable apps. Hopefully, my bitbucket account will fill up with little, tiny, reusable pieces of Python or Django goodness. Wish me luck.