Opened 17 years ago

Closed 17 years ago

Last modified 15 years ago

#5996 closed (fixed)

psycopg2 raises "can't adapt" error where other backends work happily

Reported by: Jarek Zgoda Owned by: anonymous
Component: Database layer (models, ORM) Version: dev
Severity: Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


The description is vague, but I have only vague idea on what's going on. The problem does not manifests itself with sqlite3 and psycopg backends.

I have a model with CharField. Supplying (perfectly valid) unicode object that contains non-ASCII character to this field causes the psycopg2 to raise "Can't adapt" error on saving object. The traceback I get from ipython is like this:

/home/zgoda/www/zgodowie/blog/ in save(self)
     42         if not self.slug:
     43             self.slug = slughifi(self.title)
---> 44         super(Label, self).save()

/home/zgoda/www/.python/lib/python2.4/site-packages/django/db/models/ in save(self, raw)
    257                 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
    258                     (qn(self._meta.db_table), ','.join(field_names),
--> 259                     ','.join(placeholders)), db_values)
    260             else:
    261                 # Create a new record with defaults for everything.

ProgrammingError: can't adapt 

It does not matter if I do a force_unicode() on slughifi() output, the error is the same.

The definition for the model is as follows:

class Label(models.Model):
    title = models.CharField(max_length=80, unique=True)
    slug = models.CharField(max_length=80, editable=False)
    description = models.TextField(null=True, blank=True)

    def save(self):
        if not self.slug:
            self.slug = slughifi(self.title)
        super(Label, self).save()

Attachments (1)

pg_safeunicode.diff (1.3 KB ) - added by remco@… 17 years ago.
Unit test + fix

Download all attachments as: .zip

Change History (9)

comment:1 by Jarek Zgoda, 17 years ago

Versions of libraries involved

In [2]: psycopg2.__version__
Out[2]: '2.0.6 (dec dt ext pq3)'

In [4]: psycopg.__version__
Out[4]: '1.1.21'

comment:2 by sacrebis@…, 17 years ago

I think I have the same problem, but it is related to SafeString and SafeUnicode objects.

In my case I have inclusion tag which accepts string as second argument.

{% some_inclusion_tag some_value %}

Inclusion tag code:

def some_inclusion_tag(value):
    obj = Klass.object.get(value=value)

and this raises "Can't adapt" error.

But look at that:

>>>  type(value)
<class 'django.utils.safestring.SafeUnicode'>

Could you check type of "self.title" ?

comment:3 by Jarek Zgoda, 17 years ago

The title value is ordinary unicode object, but the slug value is SafeUnicode. It looks like psycopg2 backend is unable to convert SafeUnicode to ordinary unicode object (calling unicode() does the trick).

comment:4 by remco@…, 17 years ago

Owner: changed from nobody to anonymous
Status: newassigned

comment:5 by remco@…, 17 years ago

Triage Stage: UnreviewedAccepted

We have looked at the issue as part of the 01-dec sprint. The issue is psycopg2 specific. Psycopg2 is indeed not able to adapt the SafeUnicode field even though SafeUnicode is a subclass of unicode. We are thinking about adding a psycopg adapter for the SafeUnicode type in the psycopg2 backend as proposed here:

Unit tests + patch will be added soon

comment:6 by remco@…, 17 years ago

Has patch: set
Triage Stage: AcceptedReady for checkin

Fixed by adding a field test for saving a SafeUnicode object in a model and patching the psycopg2 backend.

See attached patch for both unit test and fix.

by remco@…, 17 years ago

Attachment: pg_safeunicode.diff added

Unit test + fix

comment:7 by Malcolm Tredinnick, 17 years ago

Resolution: fixed
Status: assignedclosed

(In [6816]) Fixed #5996 -- Add a pyscopg2 convertor for SafeUnicode -> unicode. Thanks, remco@…

comment:8 by anibal, 15 years ago

I had recently a can't adapt error in a FooModel.objects.get(..., user=request.user) line

And the issue was fixed changing the line ...

Now I don't receive "can't adapt" mails from production server any more.

Note: See TracTickets for help on using tickets.
Back to Top