Am 01.10.2010 um 18:07 schrieb Luke Plant: > On Fri, 2010-10-01 at 12:16 +0200, Johannes Dollinger wrote: >> Am 01.10.2010 um 07:26 schrieb Russell Keith-Magee: >>> I've just added a summary of the last thread on class-based views >> [1]. >>> This summary isn't 100% complete -- any contributions from >> interested >>> parties are welcome. Try to keep opinions to a minimum; this page is >>> about documenting the strengths and weaknesses of various >> approaches, >>> not about expressing opinions. In the same way that CSRF [2] and >>> session-messages [3] have good wiki pages describing the design >>> considerations, we need to be able to explain to future generations >>> why class-based views are the way they are. >> >> Could you (or anyone knowledgable) add a section, that explains why >> each request should have its own view instance? >> The thread-safety argument alone does not suffice: if all _request_ >> state would be stored on request instead of the view, you wouldn't >> need new instances per request. You could also pass around state >> explicitly - which admittedly gets messy quickly. >> So is this purely about preventing users from shooting themselves in >> the foot? (hyperbole: Will there be protection from globals in django >> 1.4?) > > It's not just about stopping users from shooting themselves in the foot, > it's about helping them to do the right thing easily. Without this kind > of protection, it will be harder for *anyone*, including experienced > developers who are aware of the problem, to do things correctly. It's > like the autoescaping in templates - I *know* that I should use the > 'escape' filter, but without autoescaping it is hard for anyone to do it > right all the time. > > One alternative that has been suggested is to pass state around > explicitly, which is definitely best practice, but in many cases might > not be possible (e.g. if you are working with someone else's base class, > and in one overridden method you want to set up some objects which ought > to be available to other methods). You could also attach stateful data > to the request object, but attaching random bits of data to the request > is surely just as ugly a solution as the self.copy() call, especially if > you need to avoid names clashes with all the other attributes attached > to request. > > With regards to doing a shallow copy, it should be noted that at the > point the copy is made, the only data attached to the object is data > that has been attached in the constructor. It is of course possible that > methods within the view might mutate such data, but it seems more likely > that it will be used as immutable configuration data. > > However, I have already seen some example code that might fall foul of > this problem - someone gave the example of storing a queryset on the > object in the __init__. This will get implicitly mutated (the cache is > filled) when it is used the first time. This could lead to frustrating > problems that wouldn't be found in testing, and doing copy() on the > instance won't help. > > So, in light of the fact that developers *will* need to be aware of this > issue, I'd like to tentatively suggest an explicit solution which is > nonetheless easy to use and get right. We could have an explicit 'state' > object that is thrown away for every new request, something like this: > > class State(object): > pass > > class View(object): > def __call__(self, request, *args, **kwargs): > """ > Main entry point for a request-response process. > """ > self.state = State() > self.request = request > self.args = args > self.kwargs = kwargs > resp = self.dispatch(request, *args, **kwargs) > # let any state get GC'd immediately: > del self.state > del self.request > del self.args > del self.kwargs > return resp > > We document the issue, warn people not to store state on the instance > itself, but tell them that if they must have stateful data, it should be > attached to self.state instead of self, and they will be OK. They might > still be bitten if they put mutable configuration data into the __init__ > and it gets mutated, but we have made it easy to do the right thing - > doing 'self.state.x' is only slightly harder than 'self.x' > > Thoughts?
If you are willing to limit view state to a dedicated container, you might as well put in on request (e.g. request.view, request.state, request.context, ...) - and store args/kwargs in it as well. There would be no need to copy or clear self. It could be added automatically for all views (even those that are plain functions). However, I am -0 on the self.copy() proposal. While I believe it's the wrong design decision, I'd be happy with any decision at this point. __ Johannes -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.