Re: Class-based view decorators
Thank you all for your replies. My search on the topic had missed most of the past discussion, which I'm now catching up on. Carl Meyer wrote: > > @method_decorator(permission_required, 'thing.change_thing') > > Is this really any better than > @method_decorator(permission_required("thing.change_thing"))? > The latter seems more explicit/clearer, and allows method_decorator to > stay simpler. No, of course you're right. The nature of decorators with arguments, which are relly decorator factories, had somehow eluded me. Łukasz Rekucki wrote: > The super() problem actually makes a great Python puzzle so it's easy > to remember the dangers after solving it ;) A funny puzzle indeed. IMHO the root problem is Python 2's super() requiring an explicit mention of the surrounding class, something I never liked to begin with. It would seem the only correct way to augment classes are mixins. So until a newer Django release provides mixins (or dstufft's universal mixin-decorator classes) for all standard functionality, which seemed to be the consensus in the latest big thread, I will use a small utility to convert decorators to mixins as needed. I have attached it to the issue https://code.djangoproject.com/ticket/14512 in case someone wants to use it or augment the current documentation with it. -Tobia -- 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 django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Newline stripping in templates: the dnl way
Hi all, regarding issue #2594 "Template system should handle whitespace better" explaining the need for some kind of (optional) whitespace stripping from the output of templates, I've been looking at the proposed solutions and compared them to other template and macro engines. In particular, a historical but still widely used and general-purpose macro engine is m4. Its own feature for controlled newline stripping is the "dnl" reserved word, "Discard to Next Line." It works by "chomping" all input until and including the next newline. For example, to call a macro foo() without copying over the newline that appears after the macro call in the template, a m4 programmer would write: foo('bar`, `whatever')dnl An equivalent feature in Django templates would enable template developers to strip newlines from specific lines, while keeping backwards compatibility with existing templates. So if the general idea is well-accepted, I propose the "{#" token. The example from the issue would become: {% for item in items %}{# {{ item }} {% endfor %}{# It is already a reserved token in the template system, so it's not going to break anything. The existing comment syntax {# ... #} is already restricted to single-line comments, so there are no multi-line comments that would break. Plus, I'd wager it could be implemented quite efficiently. What do you think? Tobia -- 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 django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Re: Newline stripping in templates: the dnl way
Tai Lee wrote: > I don't think adding {# to the end of lines is easy to understand at a > glance, it doesn't even convey a hint of meaning like "dnl" does I beg to differ. {# is already recognized by template authors as meaning "start of comment", and they know (or should know) that it cannot extend through more than one line. Therefore I'd think it intuitive that it will "eat" till the end of the line and not beyond. Look: Here are your subscriptions: {% for thing in things %}{# - {{ thing.name }} You added it on {{ thing.date }} {% endfor %}{# you can manage your subscriptions... Tom Evans wrote: > I'd be strongly -1 on anything that makes template language look more > like m4! I'll tell you, m4 can be quite addictive once you grasp the basics! :) > This could be addressed by having a different open/close tag for tags > which chomp the preceeding/next character if it is a newline. Eg: > {^ for item in folder ^} I don't think adding new reserved characters would make the language simpler for template authors, nor for the the template parser, nor for the sake of backwards compatibility. {# is already part of it. But I can see the need to chomp whitespace before a template tag, as well as the newline after it. Martin J. Laubach wrote: > For this (avoiding newlines) the currently discussed multiline tags > would work pretty well too without adding more cruft to the template >language: > > foo bar {# > #}baz If this can be accomplished without massive performance penalties, I agree with you. Maybe {# #} could be made multiline at first, with special code, while waiting for a proper implementation of generic multiline tags. This would certainly be more forward-compatible than my proposal above and it would solve more whitespace problems, if not all. Tobia -- 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 django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Re: Newline stripping in templates: the dnl way
Jonathan French wrote: > Let me make sure I've got this right --- The situation being discussed is > not where whitespace is insignificant and can be stripped, but where > whitespace is important and you want to control the exact amount of it, > e.g. plain text emails. In this case, just using stripwhitespace is not > enough. Right? Yes, that is the main problem. Django templates are useful (and used) for all sorts of text-based formats. For some of these, an exact control over whitespace is needed throughout the entire file (eg. text/plain), while for others, control is needed in some sensitive places (eg. element attributes in html and xml, which according to standars are not allowed to contain literal newlines.) The only option currently available to control whitespace is *not to use any* for the template syntax itself, in effect writing long one- liners. The admin site contains several examples of such: Yes, in this case whitespace could be added between the class="" and id="" attributes, but the main issue remains there. Multiline comments {# #} and/or generic multiline tags would offer a more workable alternative than the present situation, allowing for syntax-only whitespace in templates. But they admittedly suffer from some serious ugliness and "denaturation" of Django templates. After reading all the above, I can see the arguments against this: http://groups.google.com/group/django-developers?hl=en.
Class-based view decorators
Hello As a happy user of the class-based views, I wrote a couple of higher-level decorators to make it easy to apply all the standard decorators to them. The first is an updated version of method_decorator, made to accept additional arguments and pass them to the original decorator: class MyView(View): @method_decorator(never_cache) @method_decorator(login_required, login_url='/my-login') @method_decorator(permission_required, 'thing.change_thing') def dispatch(self, request, *args, **kwargs): ... The second is class_view_decorator, to apply classic view decorators to the newer class-based views: @class_view_decorator(never_cache) @class_view_decorator(login_required, login_url='/my-login') @class_view_decorator(permission_required, 'thing.change_thing') class MyView(View): ... In the application I'm developing they seem to be working ok--and saved me quite a bit of code clutter! If you approve of this addition, I will develop proper unit tests and documentation as required. -Tobia -- 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 django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en. from functools import update_wrapper def method_decorator(decorator, *dec_args, **dec_kwargs): """ Converts a function decorator into a method decorator, with or without decorator arguments. Does not support decorators with call but without arguments: @my_dec() Example: @method_decorator(never_cache) @method_decorator(login_required, login_url='/my-login') @method_decorator(permission_required, 'thing.change_thing') def dispatch(self, request, *args, **kwargs): ... """ # 'func' is a function at the time it is passed to _dec, but will eventually # be a method of the class it is defined it. def _dec(func): def _wrapper(self, *args, **kwargs): if dec_args or dec_kwargs: @decorator(*dec_args, **dec_kwargs) def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) else: @decorator def bound_func(*args2, **kwargs2): return func(self, *args2, **kwargs2) # bound_func has the signature that 'decorator' expects i.e. no # 'self' argument, but it is a closure over self so it can call # 'func' correctly. return bound_func(*args, **kwargs) # In case 'decorator' adds attributes to the function it decorates, we # want to copy those. We don't have access to bound_func in this scope, # but we can cheat by using it on a dummy function. if dec_args or dec_kwargs: @decorator(*dec_args, **dec_kwargs) def dummy(*args, **kwargs): pass else: @decorator def dummy(*args, **kwargs): pass update_wrapper(_wrapper, dummy) # Need to preserve any existing attributes of 'func', including the name. update_wrapper(_wrapper, func) return _wrapper update_wrapper(_dec, decorator) # Change the name to aid debugging. _dec.__name__ = 'method_decorator(%s)' % decorator.__name__ return _dec def class_view_decorator(view_decorator, *args, **kwargs): """ Converts a function decorator for regular Django views, with or without decorator arguments, into a class decorator for class-based views. Example: @class_view_decorator(never_cache) @class_view_decorator(login_required, login_url='/my-login') @class_view_decorator(permission_required, 'thing.change_thing') class MyView(View): ... """ def apply_decorator(cls): # extend the original class and decorate its dispatch method class Decorated(cls): @method_decorator(view_decorator, *args, **kwargs) def dispatch(self, *args, **kwargs): return super(Decorated, self).dispatch(*args, **kwargs) # preserve name and module of the class, for debugging purposes Decorated.__module__, Decorated.__name__ = cls.__module__, cls.__name__ return Decorated return apply_decorator