As for "do we intend to solve this issue" -- you haven't been exactly
clear as to what the issue *is* -- or rather, why it isn't already
trivially solveable using completely standard OO techniques.
If you clean method on a form requires access to the request, then
just pass it in as an argument to the form. In your subclassed form,
add a keyword argument for the request.
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
# whatever self.request based validation logic is required
def my_view(request):
my_form_instance = MyForm(request=request)
# use the form instance
Problem solved, no threadlocals required. You can call this a
"workaround" if you like; I'd prefer to call it "good software
engineering practice".
Yours,
Russ Magee %-)
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers" group.
> To post to this group, send email to django-d...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-develop...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-developers?hl=en.
>
>
The real issue, as I've seen it, is not in cases such as raised by the
original poster, but in cases where the code that needs the request is located
some distance in the call-chain below the code that has access to the request;
then, solving the problem in the way Russell outlined involves having several
places in the code which accept (and sometimes, as in Russell's example, even
keep) a request object only so that they can pass it on.
As a concrete example, consider a situation where you have different pieces of
code activated in order to generate a response, and now you want to add info
from the request to your logging. I can think of no decent way to do that
except for thread-locals and a middleware (and that's actually the way I've
done it; I made sure that the middleware doesn't copy the whole request, just
the pieces I need, but still).
My 2 cents,
Shai.
This is a general problem in all software in all programming languages.
It is called the configurations problems [1], [2], and all solutions
have problems.
Making request a parameter of all objects/functions means that I can't
use those functions from a non-web context. Even making it a keyword arg
is less than desirable, because I have to alter all these functions in
the call stack, and some of them are outside my control, and some them
just don't have anything to do with web requests. Using threadlocals is
bad because it introduces global variables. However, the request is (or
ought to be treated as) an immutable global variable, which are much
better than mutable global variables, so this solution is arguably no
worse than the others. Another approach is callstack tracing to find a
request object [3], which makes threadlocals look good in comparison!
Other languages have some different solutions (Haskell has lots, because
it has a particularly powerful type system, and it suffers from this
problem much more acutely than other impure languages). I don't expect
we will come up with a new solution to it in Python.
Personally, I will use a mixture of these techniques, depending on the
context. If I use threadlocals I ensure that the code explicit handling
for the case when there is no request available.
Luke
[1] http://okmij.org/ftp/Haskell/types.html#Prepose
[2]
http://www.joachim-breitner.de/blog/archives/443-A-Solution-to-the-Configuration-Problem-in-Haskell.html
[3]
http://chris-lamb.co.uk/2010/06/01/appending-request-url-sql-statements-django/
--
"The one day you'd sell your soul for something, souls are a glut."
Luke Plant || http://lukeplant.me.uk/
I didn't think to bring other languages up here, but since you have, venerable
Common Lisp has a pretty good one in dynamically-scoped variables -- they are
like thread-locals, except that their bindings are stacked rather than
desctructive, and (essentially, in translation to Python term) bindings are
popped when the function that made them returns. This gives assignments
exactly the right level of locality. But we don't seem to have those at hand.
I
> Making request a parameter of all objects/functions means that I can't
> use those functions from a non-web context. Even making it a keyword arg
> is less than desirable, because I have to alter all these functions in
> the call stack, and some of them are outside my control, and some them
> just don't have anything to do with web requests. Using threadlocals is
> bad because it introduces global variables. However, the request is (or
> ought to be treated as) an immutable global variable, which are much
> better than mutable global variables, so this solution is arguably no
> worse than the others. Another approach is callstack tracing to find a
> request object [3], which makes threadlocals look good in comparison!
>
While callstack tracing is definitely ugly, it does give the semantics of
dynamically scoped vars, which IMHO is the best possible semantics.
But euh, at what cost!
Have fun,
Shai.