Posted by cwurld |
|
Hi Herbert,
I am getting a bug when I try to post a new thread on the sphene board on my website. Here is the error: Traceback (most recent call last): File "C:\Python24\lib\site-packages\django\core\handlers\base.py" in get_response 77. response = callback(request, *callback_args, **callback_kwargs) File "C:\Documents and Settings\CCM\Desktop\pldev\sct\communitytools\sphenecoll\sphene\sphboard\views.py" in post 190. newpost.save() File "C:\Documents and Settings\CCM\Desktop\pldev\..\pldev\sct\communitytools\sphenecoll\sphene\sphboard\models.py" in save 537. body = t.render(RequestContext(get_current_request(), c)) File "C:\Python24\lib\site-packages\django\template\context.py" in __init__ 100. self.update(processor(request)) File "C:\Python24\lib\site-packages\django\core\context_processors.py" in auth 17. return { AttributeError at /discussion/post/1/ 'NoneType' object has no attribute 'user' I have been studying the sphene\community\middleware and I am baffled how that code works. I think I know exactly why I am getting this error. What I cannot understand is why you are not getting this error. I also don't understand how the guy who posted "http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUserthreadlocals got this to work. In the middleware you have a class called ThreadLocals. This class is added to the list of middleware in settings.py. Everytime there is a request the code in this middleware that is not part of a function or class gets executed; including the line "_thread_locals = local()". Next the middleware processor makes an instance of ThreadLocals and runs the method ThreadLocals.process_request(request). This method creates a LOCAL variable called _thread_locals. This variable is not related to the one created outside of this class. If you want to convince yourself of this, run this code snippet: x='hi' class Junk: def process(self): try: print x except: print "x is not defined inside this class" x='bye' print "Now it is. x=",x c=Junk() c.process() print x Once the middleware processor completes executing ThreadLocals.process_request(request) the variable _thread_locals that is defined inside of this class ceases to exist. I am not sure what happens to the _thread_locals thread that is created by the import process. But I am guessing it ceases to exist as well. Later, when your boards model.py code runs: from sphene.community.middleware import get_current_request, get_current_user, get_current_group, get_current_session The command: _thread_locals = local() gets run again. But it does not contain any of the information from the request. In other words, the fact that the middleware processor ran ThreadLocals.process_request is irrelevant. I think this is why I am getting this error. None of the attributes from the request are defined when this module is re-imported by model.py Also, I don't think all the code on the django wiki is good. When I first started w django I posted some code on the wiki. I think it was good. But I don't really know. I never got feedback from anyone. As for a solution, have you considered passing the request to the newpost.save() function the sphboard.views? One other thing, I am not sure what the intention is in using the threading functionality in the middleware. It seems like what the author was trying to accompish is making the request and some other params into global variables that can be accessed by any module that imports that middleware. So far, I have not run into a need for something like that. But then again, I have not written anything in django as complex as sphene Best, Chuck |
|
Posted by cwurld |
|
I played with the code some more. It seems like this problem can be solved by making the variable "request" a parameter for both the save and toggle monitor methods of Post and then to get replace the get_xxx() functions in the methods with request or request.user, etc...
The code now runs without this error. I am not sure if my changes might have other unintended consequences. Chuck |
|
Posted by Herbert Poul |
|
well.. i'm going crazy .. i have nowhere found any documentation on the scope behavior i'm experiencing here :) the python documentation doesn't really help here: http://docs.python.org/tut/node11.html#SECTION0011200000000000000000
but.. finally .. i guess i can make some kind of sense out of it .. if you remove the assignment in your code example... it works.. ie. it seems python looks through the method's code to see if there is an assignment to a local variable.. and if there is none.. it uses the globally available variable.. this is very strange for me .. that by appending an assignment to a method.. you can get an UnboundLocalError a few lines above :) anyway .. i guess that's the solution of your code snippet.. i'll now try to figure out where's the problem in SCT's board ;) btw. one thing .. are you sure the body of the module is executed on each request ? it would only make sense if this is done once.. when first loading the module .. (at least with mod_python, maybe there is a difference to fastcgi) --- Last Edited by Herbert Poul at 2007-04-29 19:26:23 --- Hey, we have Signatures !!! Great, isn't it ? ;) |
|
Posted by Herbert Poul |
|
yes, that is the goal.. to have the request object globally available.. thread locals are necessary because mod_python will most probably use threads if more than one request come in at the same time.. ie. if you would just store it in a global variable you would get strange behaviour in that users would suddenly post as another user and stuff :) - it has nothing to do with the complexity of the program itself.. just in which environment it runs..
i'm using the \ThreadLocals because they were suggested to me in the django users forum: http://groups.google.com/group/django-users/browse_frm/thread/3683d5f68f7d8c1b/53eaef8cc56dabe8#53eaef8cc56dabe8 how are you running the code ? my guess is .. that it is fast cgi's fault.. i'm using mod_python on the server and the builtin ./manager.py runserver for development.. and for both the body of the middleware module is only executed once at startup .. not on each import.. could you try adding print or logging statements to see how often/when the code is executed ? --- Last Edited by Herbert Poul at 2007-04-29 19:40:22 --- Hey, we have Signatures !!! Great, isn't it ? ;) |
|
Posted by cwurld |
|
Hi Herbert,
I guessing I was too smart by half. As mentioned in previous posts, I suggested making all your code one big package with sub-packages, etc... to avoid having to add to sys.path. Well I went ahead and did that by adding empty __init__.py files to each folder. Now I could specify modules as: root.communitytools.sphenecoll.sphene.community.middleware.ThreadLocals etc... So that's how I specified stuff in my settings.py file. However to make the imports work within the other modules, I still needed to update the sys.path because the modules were being referred to as part of a package. The reason this caused the error I was seeing is when these modules were being imported using these different names, they were going into different namespaces. So I changed settings.py to specify the modules the same way in all places. I read your post to the google groups. It seems like your goal was to have request information available in your models. Why wouldn't you just pass the request as an argument in the models methods? This seems more transparent to me. I noticed that the middleware module is imported only when I start the server. This means that every request is manipulating the variable _thread_locals. It seems like it would be possible for a new request to come in before the current request is finished. Since all requests share this same variable, couldn't the new request modify it before the old request is done with it? Also, I still don't understand the need for threading at all. My understanding is that each request to the server automatically starts its own thread. I could imagine a problem with the wiki if two users tried to edit something at the same time. But I don't think the current threading would handle that problem. I hope I am not being too much of a drag on your efforts. Best, Chuck |
|
Posted by Herbert Poul |
|
i don't think i will adopt this naming .. more likely i will just move the libs into the 'sphene' directory .. so i can access them using sphene.libs.xxx .. but.. i currently want to remain the naming as sphene.community, sphene.sphboard, etc.
because in django templates you can't call a method with arguments.. so a method like 'hasNewPosts' could not be used in a normal django template if it requires an argument to be passed into it .. and i really don't like the overhead of having to create a templatetag for every method call
i think you got the meaning wrong .. nowhere in this code is a thread started or something.. just a thread local variable is created.. ie. everything you assign to _thread_locals is only available in the current thread.. ie. it creates a new scope for every thread.. ie. let's say you are using mod_python with apache workers.. which makes it (imho) very likely that if two requests come in at the same time come in .. they are just two threads .. since the module was already imported on server startup .. the module's body is not executed.. and the _thread_locals variable is already filled.. then the middleware is executed for the first request.. which assigns _thread_locals.xxx = .. at the same time the second request would execute the same method.. add assign it's request.. but it won't overwrite the old one because it's running in a second thread.. (thread locals are.. as the name say .. local to the current thread, and not accessible/overwriteable in other threads) .. i have no experience with python thread locals.. but in java thread locals are simply implemented by having a Map (dictionary) where you have the thread id as key, and your variable as value.. this way you can only access the data for your own thread.. i hope this makes it clearer ;) Hey, we have Signatures !!! Great, isn't it ? ;) |
|
Posted by cwurld |
|
Hi Herbert,
Thanks for the excellent reply. Sorry for leading you on a wild goose chase. I will move ahead with everything as you designed it. My next challenge is to integrate it with my customized auth system. Thanks again, Chuck |
Please login to post a reply.