Database race conditions when using multiple processes

2006-10-16 Thread Thomas Steinacher

Hello,

I was recently using the get_or_create method and noticed that it added
an entry twice into my database in very rare cases, because it
complained later that "get() returned more than one ___ -- it returned
2!". This problem didn't occur when using the development server.

My question is: Is there a way to avoid these race conditions by e.g.
locking the database? How can I do that?

This is my setup:

- Django (SVN) running with "python manage.py runfcgi method=prefork"
(there are 6 processes running)
- Lighttpd
- SQLite

To prove the race condition, I used the following model:

class Test(models.Model):
str = models.CharField(blank=True, null=True, maxlength=100)

The relevant part of my urls.conf is:

# Testing
(r'^test/$', 'test.main'),
(r'^test/process/$', 'test.process'),

And here's the view:

--- CUT HERE ---

from django.http import HttpResponse

import models
from json import load

def main(request):
return HttpResponse("""



http://prototype.conio.net/dist/prototype-1.4.0.js";
type="text/javascript">
http://www.json.org/json.js";
type="text/javascript">


function send_request(callback, text)
{
new Ajax.Request('process/' /* URL */, {
postBody:'text='+encodeURIComponent(text),
onComplete:callback
});
}

function debug(str)
{
var date = new Date();
str = date.toTimeString().substr(0, 8)+' '+str+'
'; $('debug').innerHTML = str+$('debug').innerHTML; } function cb(req) { if (req.status == 200) debug('Received response: '+req.responseText); else debug('error '+req.status+' '+req.responseText); } function clicked() { send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); send_request(cb, $('text').value); } test """) def process(request): if request.POST.get('text'): t = models.Test.objects.get_or_create(str=request.POST.get('text'))[0] return HttpResponse('%s %s' % (request.POST.get('text'), t.id)) else: return HttpResponse('Missing argument') --- CUT HERE --- When I play around with it, I sometimes get this debug output followed by an AssertionError (notice the different IDs): 20:07:41 Received response: blah 21 20:07:41 Received response: blah 19 20:07:41 Received response: blah 20 20:07:41 Received response: blah 19 I know that in this specific case it can be enforced at database level using the unique and unique_together properties, but how would you handle e.g. this scenario? 1 def transfer_money(from_id, to_id, amount) 2from = models.BankAccount.objects.get(id=from_id) 3to = models.BankAccount.objects.get(id=to_id) 4from.balance -= amount 5to.balance += amount 6from.save() 7to.save() What, if two Django processes transfer money from account A to account B simultaneously? tom --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---

Re: Database race conditions when using multiple processes

2006-10-16 Thread Thomas Steinacher

On Oct 16, 2006, at 8:46 PM, gabor wrote:
> > What, if two Django processes transfer money from account A to account
> > B simultaneously?
>
> these situations are (afaik) handled using transactionssimply start
> a transaction at the beginning, and commit/rollback at the end...

I already included
"django.middleware.transaction.TransactionMiddleware" in my
MIDDLEWARE_CLASSES (as described on
http://www.djangoproject.com/documentation/transactions/#tying-transactions-to-http-requests)
and it didn't help.

tom


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Database race conditions when using multiple processes

2006-10-16 Thread Thomas Steinacher

gabor wrote:
> Thomas Steinacher wrote:
> > I already included
> > "django.middleware.transaction.TransactionMiddleware" in my
> > MIDDLEWARE_CLASSES (as described on
> > http://www.djangoproject.com/documentation/transactions/#tying-transactions-to-http-requests)
> > and it didn't help.
> >
>
> you mean it did not help with the money-transfer code?
>
> gabor

It did not help with the code I posted that was using get_or_create(),
because I didn't use unique_together... I don't think it would help
with the money-transfer code.

The documentation says:

"It works like this: When a request starts, Django starts a
transaction. If the response is produced without problems, Django
commits any pending transactions. If the view function produces an
exception, Django rolls back any pending transactions."

The problem is that the code doesn't produce an exception, so Django
will not roll back anything...

tom


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Database race conditions when using multiple processes

2006-10-17 Thread Thomas Steinacher

James Bennett wrote:
> On 10/16/06, gabor <[EMAIL PROTECTED]> wrote:
> > would you use something in the db? (from what i know about transactions
> > (very little :), they "solve" the potential conflicts by simply
> > reporting an error-condition to one of the "writers", so then he has to
> > retry. but is there some simply (multiprocess-usable) way to lock (as in
> > "wait until this guy is finished")?
>
> http://www.postgresql.org/docs/8.1/static/sql-lock.html

This is PostgreSQL specific. There seems also to be something like that
for MySQL: http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html (it
looks like you have to do an UNLOCK TABLES on MySQL, whereas PostgreSQL
releases the lock at transaction end).

Shouldn't there be a function built-in into Django that locks the table
(if the database supports it)? IMHO functions like get_or_create()
should try to lock and unlock the table automatically.

I am not doing critical operations like transferring money, but I
noticed that the race condition happens quite often when using
get_or_create and a lot of AJAX requests, so I need to find a solution.

I will try using PostgreSQL instead of SQLite, maybe this will reduce
the probability of the race condition to happen ;-)

tom


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Database race conditions when using multiple processes

2006-10-17 Thread Thomas Steinacher

Michael Radziej wrote:
> It seems you need to spend more thoughts on multi user issues
> within your application. It's easy to fall for that in the
> beginning, but you need to deal with concurrent access. You must
> be aware for all transactions what impact other transactions can
> have. There is no silver bullet ... (please repeat ;-)
>
> > I will try using PostgreSQL instead of SQLite, maybe this will reduce
> > the probability of the race condition to happen ;-)
>
> Hmm, this might be a first step, but it won't magically solve all
> multi user issues. This *is* hard stuff.

Simply switching to PostgreSQL didn't solve anything. The race
condition was still there.

I am not sure but I think that a lock would be okay for my application,
as I don't want to deal with exceptions. What do you think about the
following code?


def process(request):
if request.POST.get('text'):
cursor = connection.cursor()

# Acquire a lock
cursor.execute('LOCK TABLE testapp_test IN ACCESS EXCLUSIVE
MODE')
t =
models.Test.objects.get_or_create(str=request.POST.get('text'))[0]

# Release the lock
transaction.commit()

return HttpResponse('%s %s' % (request.POST.get('text'), t.id))
else:
return HttpResponse('Missing argument')
process = transaction.commit_manually(process)


tom


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Bug in documentation

2006-11-09 Thread Thomas Steinacher

Hello,

I'm posting it here because Akismet is blocking my ticket. Can't you
use captchas instead of a stupid spam detector?


Session.objects.get_object() should be Session.objects.get()

On
http://www.djangoproject.com/documentation/sessions/#using-sessions-out-of-views
it says:

{{{
>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get_object(pk='2b1189a188b44ad18c35e113ac6ceead')
}}}

However, it should be:

{{{
>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
}}}

tom


--~--~-~--~~~---~--~~
 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
-~--~~~~--~~--~--~---



newforms:

2006-12-25 Thread Thomas Steinacher


Hello,

In newforms, there should be an easy way to render the radio fields
separately in the template, because I'd like to insert other form
fields between the radio inputs, e.g.:

[o] Use existing one: []
[ ] Add a new one: []

At the moment (using widget=forms.RadioSelect) all radio items are
rendered in a list and I can't insert anything between them.

I'd like to be able to do something like this:


{{ form.radio_options.1 }}: {{ form.foo }}
{{ form.radio_options.2 }}: {{ form.bar }}


What do you think?

Thomas Steinacher


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



newforms: rendering radio fields separately

2006-12-25 Thread Thomas Steinacher


Hello,

In newforms, there should be an easy way to render the radio fields
separately in the template, because I'd like to insert other form
fields between the radio inputs, e.g.:

[o] Use existing one: []
[ ] Add a new one: []

At the moment (using widget=forms.RadioSelect) all radio items are
rendered in a list and I can't insert anything between them.

I'd like to be able to do something like this:


{{ form.radio_options.1 }}: {{ form.foo }}
{{ form.radio_options.2 }}: {{ form.bar }}


Or maybe something like this:

{% for opt in form.radio_options %}{{ opt }}{% endfor %}


What do you think?

Thomas Steinacher

P.S.: I sent this mail earlier but it didn't appear in the mailing list
for some reason... And google doesn't let me post using my e-mail
client :-(


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



newforms: Creating a Widget with multiple HTML form elements

2006-12-27 Thread Thomas Steinacher


Hello,

Sometimes it would useful to create a FormField with a Widget that
consists of multiple HTML form elements. Rendering such a widget is
very easy, however, I don't see a possibility to get the data in the
clean() method of the Field. There should be an easy way to get the
data. Maybe by assigning multiple names for a field?

Consider the example below. I need this contact info in multiple forms
and I don't want to define all three fields in every form.


class ContactInfoWidget(forms.Widget):
   def render(self, name, value, attrs=None):
   print name
   TYPES = (
   (_('Main contact'), 'main_contact'),
   (_('Billing contact'),'billing_contact'),
   (_('Technical contact'), 'technical_contact'),
   )
   emails = ('[EMAIL PROTECTED]','[EMAIL PROTECTED]')

   return '\n%s\n' % (
   ''.join(['  %s: %s %s\n' %
   (type, name, type_name, ''.join(['%s'
% email for email in emails]), _('Other...'))
   for type, type_name in TYPES]))

class ContactInfoField(forms.Field):
   widget = ContactInfoWidget

   def __init__(self, required=True, widget=None, label=_('Contact
info')):
   forms.Field.__init__(self, required, widget, label)
   def clean(self, value):
   print value
   return value


Thomas Steinacher


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Is this group moderated, or is it a bug with google groups?

2007-01-26 Thread Thomas Steinacher

Yeah, google groups sucks. Using my gmail.com account it sometimes  
takes up to three days until a message appears. I also couldn't post  
to the list using a non-gmail account. It says that I'm not  
subscribed to the list, but I am.

tom


On Jan 26, 2007, at 7:49 AM, medhat wrote:

>
> So many times I send messages to the group, but my message does not
> appear at all, or it might appear a day or two after I actually send
> it, which of course makes it appear down on the list, and nobody  
> really
> sees it.
>
> -- 
> Thanks,
> Medhat
>
>
> >


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Is this group moderated, or is it a bug with google groups?

2007-01-26 Thread Thomas Steinacher

This is funny. Now it seems to work. It didn't work for months.

tom


On Jan 26, 2007, at 6:30 PM, Thomas Steinacher wrote:

>
> Yeah, google groups sucks. Using my gmail.com account it sometimes
> takes up to three days until a message appears. I also couldn't post
> to the list using a non-gmail account. It says that I'm not
> subscribed to the list, but I am.
>
> tom


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



newforms: Dynamic forms using JavaScript

2007-02-15 Thread Thomas Steinacher

Hello,

I created a small library called "dynamicforms" (based on newforms)  
that allows you to edit multiple instances of an object  
simultaneously. It also provides a JavaScript link that allows you to  
add another instance of the object without having to reload the page.

Take a look at it:
http://eggdrop.ch/blog/2007/02/15/django-dynamicforms/

Maybe this could be improved and integrated into Django (see also  
ticket #3433)? Comments are appreciated.

tom


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Proposal: Root view

2007-02-19 Thread Thomas Steinacher

Hello,

What is the current status of the ROOT_VIEW setting?

Are there any plans to implement this?

I am +1 on this, because it would allow me to use one Django instance  
for multiple subdomains, without wasting system ressources. Also,  
this is more flexible than e.g. a HostURLResolver (see http:// 
code.djangoproject.com/ticket/1192).

Thomas


On Nov 21, 2006, at 6:22 AM, Adrian Holovaty wrote:

>
> Currently, Django uses the ROOT_URLCONF to determine which module
> contains the URLconf from which to start processing the URL. Simon
> Willison and I were discussing this a while ago, and he had the idea
> of turning things around to make things more flexible.
>
> Instead of a ROOT_URLCONF setting, we could have a ROOT_VIEW setting,
> which would point to a single view function that acts as the site
> root. The URLconf, then, would *become* a view -- that is, patterns()
> would return an object whose __call__() method took an HttpRequest
> object and returned an HttpResponse. The logic of this view would
> simply implement the regular expression lookup stuff that the URLconf
> infrastructure currently uses.
>
> Why make this change? At first, it seems like it wouldn't be much
> different than the way Django currently works. But consider these
> advantages to a ROOT_VIEW setting:
>
> * All of a sudden URL traversal gets way more flexible. Your root view
> can delegate to Django's URLconf for a certain app, or some other URL
> traversal library (e.g., Routes) for another piece of the URL tree.
>
> For instance, you could set your root view to this:
>
> def my_root_view(request):
> if request.path.startswith('/foo/'):
> # Do something special
> return parse_urlconf(request, my_urlconf)
>
> (In this example, the framework would provide the parse_urlconf  
> view function.)
>
> * The processing of requests gets conceptually simpler. The whole
> shebang is just a single view function, and the URLconf happens to be
> a "configurable" view function.
>
> * It would make it dead simple to do a web.py-ish "all in a single
> module" application, by providing a run_django() function that took a
> view and treated it as the root view:
>
> if __name__ == "__main__":
> run_django(root_view)
>
> This would also make testing simpler.
>
> * It would make view decorators more flexible. You could apply a view
> decorator to a selection of views, for instance. This might even make
> middleware unnecessary, but I haven't fully thought about that.
>
> * Oh, and it would be easy to make this fully backwards compatible.
>
> Thoughts, criticisms?
>
> Adrian
>
> -- 
> Adrian Holovaty
> holovaty.com | djangoproject.com

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: newforms: compound or nested forms

2007-03-09 Thread Thomas Steinacher

+1 - Sub forms and form lists are great and IMHO very common. Please
submit the patch.

On Mar 9, 11:18 am, "Jeroen van Dongen" <[EMAIL PROTECTED]> wrote:
> Apart from the SubForm "field" I've also created a FormList "field"
> which takes a form definition, a min_count and a max_count which
> allows for easy creation of a whole list of identical forms (think
> edit_inline=models.STACKED).

How would you render a FormList in a template? Would it be possible to
render the FormList using JavaScript, to make it possible to add new
items by clicking on a JavaScript link? I did something similar:
http://eggdrop.ch/blog/2007/02/15/django-dynamicforms/ Maybe this
could be combined...

Thomas


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Templates: short comments {##} eats text

2007-04-26 Thread Thomas Steinacher


On Apr 26, 2007, at 4:40 PM, tonnzor wrote:

>
> This feature is demanded and it is easy to implement w/o side effects.
> We should do it.

+1




--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Templates: short comments {##} eats text

2007-04-26 Thread Thomas Steinacher

But then it should be at least mentioned in the documentation that  
this tag works only on a single line and will cause unexpected  
results when used on multiple lines (or better: raise an exception  
when using multiple lines).

Thomas


On Apr 26, 2007, at 9:46 PM, James Bennett wrote:

>
> On 4/26/07, tonnzor <[EMAIL PROTECTED]> wrote:
>> This feature is demanded and it is easy to implement w/o side  
>> effects.
>> We should do it.
>
> The ticket for this has been closed multiple times and Adrian has
> asked that it not be reopened. Malcolm has asked that this thread be
> allowed to die. That seems to indicate that a decision has been made
> and that the proposed changes will not be implemented; regardless of
> whether you agree with it or not, please respect that and allow the
> list to move on to discussing other things.


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



Re: Problems with FileFields/ImageFields

2007-11-17 Thread Thomas Steinacher

Hello,

Maybe the snippet which I created today can help you. It displays a  
delete checkbox next to the :
http://www.djangosnippets.org/snippets/469/

However, I'm not sure if it will work in admin.

tom

On 16.11.2007, at 18:12, Marc Garcia wrote:

>
> There are a couple of things about FileFields that I want to comment.
>
> First one is about how to delete content in a FileField. With a
> example:
>
> I've a model:
>
> class Person(model.Model):
>name = models.CharField(maxlength=32)
>[...]
>picture = models.ImageField(upload_to='pictures', blank=True)
>
> Imagine that I've created a person record with a picture of anoother
> person, and I want to delete it (the picture). How can I do? I think
> that in admin it should be a checkbox for FileFields to remove
> content.
>
> Second problem that I have. With an example as well.
>
> In last application I want my users to upload its own data, so I
> create a page with a form generated with form_for_model for previous
> model.
>
> When displayed, for a user that already exists, and already has a
> picture, an empty  is displayed for picture
> field. User can't see it's own picture with admin's link, and when
> saved, old picture is dropped. I think that it should work like in
> admin (with delete checkbox).
>
> Please, comment me what you think about and if necessary I'll develop
> fixing patches.
>
> Thanks!
>  Marc


--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---