Hi all :)

I have the following problem.

I have a function that do some get_or_create on model X giving as
parameters the field Y and Z. The same function is running on
different threads, so it can happen that more get_or_create on model X
and fields Y/Z are called at the same time. It can also happen that
the values of Y/Z are the same in the different threads and here it
comes the problem: it happens that get_or_create says it returned more
than one row for X-Y/Z.

Now Y/Z are not unique in my model and I do not have an overloading of
the save function, but I think I can have the same problem if Y/Z were
unique too.

Looking at the DB I have more than one row with same values...how
comes this? Here the get_or_create...

    def get_or_create(self, **kwargs):
        """
        Looks up an object with the given kwargs, creating one if
necessary.
        Returns a tuple of (object, created), where created is a
boolean
        specifying whether an object was created.
        """
        assert len(kwargs), 'get_or_create() must be passed at least
one keyword argument'
        defaults = kwargs.pop('defaults', {})
        try:
            return self.get(**kwargs), False
        except self.model.DoesNotExist:
            params = dict([(k, v) for k, v in kwargs.items() if '__'
not in k])
            params.update(defaults)
            obj = self.model(**params)
            obj.save()
            return obj, True

Well...looking at the function I can say it happens in this way (and I
did by debug too) :

time 1 : T1 (thread 1) call get_or_create and does the self.get and it
goes in exception for DoesNotExists
time 2 : T2 do the same and goes in exception too for the same reason
time 3 : T1 goes on with the exception and creates the object and
gives it back
time 4 : T2 the same (creating another one!)
time 5 : any T (T1 or T2 or T3) who calls get_or_create again with
same X-Y/Z...the self.get gets crazy.

If the Y/Z were unique I just think the whole thing would fail at time
4...a little bit different, but still a problem.

I could solve all the thing in this way, but I hope there is a better
solution that I'm missing :

from threading import Lock
lock = Lock()

    def get_or_create(self, **kwargs):
        """
        Looks up an object with the given kwargs, creating one if
necessary.
        Returns a tuple of (object, created), where created is a
boolean
        specifying whether an object was created.
        """
        assert len(kwargs), 'get_or_create() must be passed at least
one keyword argument'
        defaults = kwargs.pop('defaults', {})
        try:
            return self.get(**kwargs), False
        except self.model.DoesNotExist:

            lock.acquire()
            try :

                try :
                    res = self.get(**kwargs), False
                except self.model.DoesNotExist:
                    params = dict([(k, v) for k, v in kwargs.items()
if '__' not in k])
                    params.update(defaults)
                    obj = self.model(**params)
                    obj.save()
                    res = obj, True

            except Exception, e:
                lock.release()
                raise e

            lock.release()
            return res


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

Reply via email to