On Thu, 2007-03-15 at 15:07 +0000, Jeff Forcier wrote:
> Thanks a lot for the reply, Malcom!
> 
> Here's an example of the sort of urlconf/view setup that I've got. The
> code has some legacy junk that looks odd (like 'session_extract'
> instead of simply calling request.session.xyz) but is there due to a
> previous server setup. I'm porting this code to 0.95 in my trunk, too--
> I know it looks pretty crufty compared to current Django setups =)
> 
> ### urls/engagements.py
> 
> base_info_dict = {
>     'extra_context': {
>         'placeholder': PLACEHOLDER,
>         'roles': {
>             'can_edit': ROLES.cases.submitter,
>         },
>     }
> }
> 
> info_dict = dict(base_info_dict,
>     app_label='cases',
>     module_name='cases',
> )
> 
> # Has a dozen or so other urlconfs, just left a few in for examples -
> they are all similar, using just 'info_dict'
> # or adding in the template name as well.
> urlpatterns = patterns('',
>     (r'^
> $','intranet.apps.base.views.base.render_with_roles',dict(info_dict,template='cases/
> index')),
>     # ...
>     (r'^new/$','intranet.apps.cases.views.cases.new',info_dict),
>     # ...
>     (r'^conflicts/
> $','intranet.apps.cases.views.engagements.conflicts',dict(info_dict,template='cases/
> conflicts')),
> )
> 
> 
> ### views/cases.py
> 
> def new(request,**kwargs):
>     return update_or_new(request,False,**kwargs)
> 
> def update_or_new(request,update,**kwargs):
>     # Get manipulator
>     try:
>         if kwargs.has_key('case_id'):
>             kwargs['object_id'] =
> cases.get_object(client__pk=kwargs['company_id'],pk=kwargs['case_id']).id
>         if update:
>             manip = cases.ChangeManipulator(kwargs['object_id'])
>         else:
>             manip = cases.AddManipulator()
>     except cases.CaseDoesNotExist:
>         raise Http404
> 
>     # Form processing cut out for brevity
> 
>     context = {
>         'form': form,
>         'user': request.user_dict,
>         'info_message': session_extract(request,'info_message'),
>         'is_case_manager':
> check_role(request.user_dict,ROLES.cases.manager),
>     }
>     context.update(kwargs['extra_context']) # This is the kwarg that
> is getting messed up half the time
>     return base.render(request,'cases/cases_form', context)
> 
> 
> ### views/base.py
> 
> def render(request,template_name,context):
>     '''Semi-replacement for render_to_response which uses
> DjangoContext.'''
>     t = get_template(template_name)
>     c = DjangoContext(request,context)
>     return HttpResponse(t.render(c))
> 
> 
> So while I don't technically have any mutable types as default
> arguments, I am passing in dicts via the URLconf 'info_dict' variable,
> and I do modify 'kwargs' in-place in my views (often because I have a
> two- or three-long chain of views before the actual response is
> returned, as shown).

So the code you posted doesn't look too bad, but this comment that you
are updating kwargs in place sets off alarms.

> If that's the culprit, then I don't understand why it's causing the
> problems I'm seeing - wouldn't each URL tuple -> RegexURLPattern
> object -> view method 'collection' be insulated from the others? If I
> read it correctly there's one RegexURLPattern instance created per
> URL, so I don't see how the data stored in their attributes would be
> shared or otherwise mixed up.

There is only one copy of the object attached to
base_info_dict['extra_context'] floating around. Everywhere you use it,
it will be referred to by reference, not by value. That single copy is
created at the moment you import your urls.py file. Anybody who updates
that instance will have their changes visible to every other user of
that dictionary (within the same process -- so you will see problems
across threads in a multi-threaded environment and between successive
requests even within a single thread).

Remember that when you do something like foo.update(base_info_dict) (or
create a new dictionary from it), Python does not call copy() on the
values it is using for the new dictionary: internally, it just
increments the reference count. This is generally a *good* thing, but
sometimes it can bite you in the backside.

If you are updating base_info_dict['extra_context'] directly or
indirectly at any point in your code, stop doing it. Make a copy of that
dictionary first and only update the copy. I realise you only posted a
portion of your code above, but keys like "placeholder" make me suspect
you are actually replacing the value with something later on, which will
ruin your day in just the way you are seeing.

> Finally, I should point out that at least on my development server, I
> am seeing the problem even when only requesting one URL; in other
> words, the server is serving requests for a single URL, multiple times
> in a row, with no other URLs being requested at all, and is ending up
> with different results each time.

That would be consistent with the above.

Regards,
Malcolm


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@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-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to