diff --git a/django/core/db/backends/postgresql.py b/django/core/db/backends/postgresql.py index b1b2d9cb52..fa587f01ca 100644 --- a/django/core/db/backends/postgresql.py +++ b/django/core/db/backends/postgresql.py @@ -9,6 +9,38 @@ import psycopg as Database DatabaseError = Database.DatabaseError +def smart_basestring(s, charset): + if isinstance(s, unicode): + return s.encode(charset) + return s + +class UnicodeCursorWrapper(object): + """ + A thin wrapper around psycopg cursors that allows them to accept Unicode + strings as params. + + This is necessary because psycopg doesn't apply any DB quoting to + parameters that are Unicode strings. If a param is Unicode, this will + convert it to a bytestring using DEFAULT_CHARSET before passing it to + psycopg. + """ + def __init__(self, cursor, charset): + self.cursor = cursor + self.charset = charset + + def execute(self, sql, params=()): + return self.cursor.execute(sql, [smart_basestring(p, self.charset) for p in params]) + + def executemany(self, sql, param_list): + new_param_list = [tuple([smart_basestring(p, self.charset) for p in params]) for params in param_list] + return self.cursor.executemany(sql, new_param_list) + + def __getattr__(self, attr): + if self.__dict__.has_key(attr): + return self.__dict__[attr] + else: + return getattr(self.cursor, attr) + class DatabaseWrapper: def __init__(self): self.connection = None @@ -33,6 +65,7 @@ class DatabaseWrapper: self.connection.set_isolation_level(1) # make transactions transparent to all cursors cursor = self.connection.cursor() cursor.execute("SET TIME ZONE %s", [TIME_ZONE]) + cursor = UnicodeCursorWrapper(cursor, settings.DEFAULT_CHARSET) if DEBUG: return base.CursorDebugWrapper(cursor, self) return cursor