On Fri, Mar 26, 2010 at 1:49 AM, Kenneth Gonsalves <law...@au-kbc.org>wrote:

> Here is what I mean - A simple model with two fields, 'name' is unique,
> and 'num' is not null:
>
> >>> Tm.objects.get_or_create(name='me',num=1)
> (<Tm: me>, True)
> >>> Tm.objects.get_or_create(name='me',num=2)
>

If you want get_or_create to return the instance with name 'me', regardless
of the value of num which that instance may have, then you need to include
the num value in the defaults argument to get_or_create, NOT as a bare
keyword argument. From
http://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create-kwargs
:

"Any keyword arguments passed to get_or_create() -- except an optional one
called defaults -- will be used in a get() call."

So with the arguments as you have passed them, get_or_create is looking for
a model with name='me' and num=2, and since one does not exist, it is going
to go down the path of attempting to create an instance with those values.
Since you have specified at the database level that name must be unique,
that is not going to work: attempting to create a 2nd row with an
already-existing name value is going to raise an IntegrityError.

To accomplish what you want, you need to move num into the defaults
argument, so that it will not be used on the get() lookup, but will be used
if the get fails to find a match and an object needs to be created. That is:

Tm.objects.get_or_create(name='me', defaults={'num': 2})


Traceback (most recent call last):
> [snip]
>   File "/usr/lib/python2.6/django/db/backends/__init__.py", line 61, in
> _savepoint_rollback
>    self.cursor().execute(self.ops.savepoint_rollback_sql(sid))
>  File "/usr/lib/python2.6/django/db/backends/__init__.py", line 75, in
> cursor
>    cursor = self._cursor()
>  File "/usr/lib/python2.6/django/db/backends/postgresql/base.py", line 149,
> in _cursor
>    cursor.execute("SET client_encoding to 'UNICODE'")
> ProgrammingError: ERROR:  current transaction is aborted, commands ignored
> until end of transaction block
>
> SET client_encoding to 'UNICODE'
>

Here you are running into a bug in the postgresql backend.  Is there some
reason you are using the old psycopg1 backend instead of the psycopg2 one?
The latter is really a much better choice at this point.

Anyway, what has happened here is the get_or_create code has gone down the
path of trying to create the new object, which has failed because of the
unique constraint on name. It is trying to rollback to the
previously-created savepoint, but that is failing due to a bug that was
fixed yesterday in r12848 (trunk) and r12849 (1.1.X branch).  So to avoid
this you could either simply switch to the psycopg2 backend (which did not
have the bug) or update to a latest trunk or 1.1.X Django code.

Note when you fix the call to get_or_create to properly specify which of the
values must be used on the get() part of get_or_create(), you won't be going
down this path as you are now, so you likely won't see this exception during
basic testing even if you don't change backends or update to latest Django
code. However, you could still go down this path legitimately -- if two
threads "simultaneously" attempt to create an object with the same name,
both may see that it does not exist and try to create it. Only one will
succeed, and the other will go down this path. You'll need this path to work
properly in order for the 2nd thread to be able to retrieve the object
created by the other thread. So even if you notice that fixing the
get_or_create call makes this other exception go away, you should still
update the code you are using, if you want the call to behave correctly in
all situations.

Karen

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-us...@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.

Reply via email to