Re: RFC: "universal" view decorators
Hi all, Haven't seen a comment on this topic for a few days, so was wondering if a core dev can make a design decision yet. I have some spare time in the remainder of this week, so if the (universal) decorator- approach is chosen, I should be able to finish it shortly (the mixin- approach is a bit harder to estimate). Cheers, Roald On Sep 17, 2011, at 4:32 AM, Alex Gaynor wrote: On Fri, Sep 16, 2011 at 10:27 PM, Donald Stufftwrote: unittest.skip isn't a Mixin, it turns the class into an exception and raises it. It doesn't *turn* a class into anything, it simply returns a function, instead of a new class, and the function raises SkipTest, the point wasn't the implementation detail, but rather the syntax and pattern at work. django.test.utils.override_settings is a mixin and it's terrible, it dynamically creates a new subclass, and overrides 2 methods. It's magic and more complex then need be. a) it's not a mixin b) yes, it creates subclasses, because the alternative is mutating the original class, which isn't how people generally expect decorators to work, we expect them to be syntactic sugar for: A = wrap(*args)(A) such that we can also do B = wrap(*args)(A) and have two classes (or functions). c) I'm not sure how it's magic, but certainly if it's too complex we'd take patches to simplify the implementation. On Friday, September 16, 2011 at 9:50 PM, Alex Gaynor wrote: On Fri, Sep 16, 2011 at 9:47 PM, James Bennett wrote: We have the following constraints: 1. Django supports class-based views. 2. Django supports function-based views (ultimately these are the same thing, which is that Django supports anything as a 'view' so long as it's callable, accepts an HttpRequest as its first positional argument when being called and either returns an HttpResponse or raises an exception). 3. The natural way to add processing in/around a class is subclassing and either overriding or mixing in. 4. The natural way to add processing in/around around a function is decorating. Any solution to this needs to address those constraints, and allow code to look and feel natural. Based on that, some arrangement which allows the same basic logic to exist in a "mixin" (I dislike that word) for classes and a decorator for functions seems most appropriate, even if it does mean having two ways to do things -- that's a distinction I think we can live with, as people will appreciate that it doesn't result in strange-looking code. I agree with all your points, except #3, I think it's an over simplification. There's another way to change a class: class decorators. And there's ample precedent for their use in such a manner, unittest's skip decorators, our own decorators for swapping settings during testing, etc. Alex Alex -- 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: ManyRelatedManager with explicit intermediary model
On Sep 20, 2011, at 5:50 PM, Tom Evans wrote: On Tue, Sep 20, 2011 at 4:12 PM, Roald de Vries <downa...@gmail.com> wrote: I don't see how this is different from the create method on the intermediary model. Cheers, Roald PS: I found an open ticket on this, https://code.djangoproject.com/ticket/9475 Here is the function definition for add() on related object manager: add(obj1[, obj2, ...]) As you can see, it can be used to add multiple objects to the relationship in one go, and therefore the arguments to this function would need to change to support what you propose. This would require going through the whole deprecation procedure (2/3 major releases before it is gone), and I guess the pain outweighs the gain on that one. add(*objs, **kwargs) is backward compatible with add(*objs), so that's not the reason a deprecation procedure is needed. The thing that might be considered backward incompatible is the fact that with this new feature, the 'add' method is also defined on ManyRelatedManagers with explicit intermediary models. create() takes **kwargs, but those arguments relate to the instance being created on the other end of the relationship, there would still be no way to specify non-default values for the intermediate model. You would have to do something similar to passing a defaults dictionary to create(), which then makes it different to how create() on an object manager works, and introduces another field that you would have to do some magic to work around. I guess the main thing is what's the point? The argument is over which of these is prettier: model_a_instance.modelb_set.add(model_b_instance) and Intermediate.objects.create(model_a=model_a_instance, model_b=model_b_instance) Beauty contests in code are rather pointless - the documentation has for a long time said that the latter is the only way you can do it, and most developers are now used to that. I don't want to forbid the second form, you may still use it if you like it better. For me, it seems more consistent (which I think is more beautiful) to create a relation between 2 instances from one of the instances, because I always access the other instance through the ManyRelatedManager on the one. If there are enough people that like the first form, then that's the point. -- 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: ManyRelatedManager with explicit intermediary model
On Sep 20, 2011, at 4:23 PM, Stephan Jaensch wrote: Am 20.09.2011 um 15:52 schrieb Roald de Vries: Is there a fundamental reason that I'm missing (other than "nobody's taken the trouble of writing it") that I can't do the following? If there isn't I'll create a ticket for it. class R(Model): user = ForeignKey(User) my_model = ForeignKey('MyModel') comment = CharField(max_length=100, blank=True) class MyModel(Model): users = ManyToManyField(User, through=R, null=True) m = MyModel.objects.create() u = User.objects.create_user('roald', 'downa...@gmail.com', 'password') # these things I can't do: m.users.add(u) m.users.add(u, comment='Blablabla') https://docs.djangoproject.com/en/1.3/topics/db/models/#intermediary- manytomany You can't use add() when specifying the intermediate model. You would have to check all fields of the intermediate model and make sure all of them have defaults or are allowed to be null. It might not be worth the trouble of implementing it. I don't see how this is different from the create method on the intermediary model. Cheers, Roald PS: I found an open ticket on this, https://code.djangoproject.com/ticket/9475 -- 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.
ManyRelatedManager with explicit intermediary model
Hi all, Is there a fundamental reason that I'm missing (other than "nobody's taken the trouble of writing it") that I can't do the following? If there isn't I'll create a ticket for it. class R(Model): user = ForeignKey(User) my_model = ForeignKey('MyModel') comment = CharField(max_length=100, blank=True) class MyModel(Model): users = ManyToManyField(User, through=R, null=True) m = MyModel.objects.create() u = User.objects.create_user('roald', 'downa...@gmail.com', 'password') # these things I can't do: m.users.add(u) m.users.add(u, comment='Blablabla') Cheers, Roald -- 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: RFC: "universal" view decorators
On Sep 16, 2011, at 6:19 PM, Donald Stufft wrote: Documentation is being worked on, and is orthogonal to the current discussion of how to handle things like requiring logins with the new CBVs. I just watched "Class Decorators: Radically Simple" by Jack Diederich, who wrote the class decorators PEP, and I think it's very useful to watch (25 min.) for this discussion. According to him it is good practice to return the class that is decorated, which I think we should follow, and which solves the biggest practical problems with decorating. Moreover, the fact that class decorators exist indicate that they are pythonic. So +1 for the decorators. Considering the mixins: IMHO, the order of base classes shouldn't matter. Can this be satisfied by the mixin-approach? @Carl Meyer: I would opt for applying decorators *in* the class, so you can still derive from it. Like:: class MyView(View): @classonlymethod def as_view(cls, *args, **kwargs): return login_required(super(MyView, cls).as_view(*args, **kwargs)) Cheers, Roald -- 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: RFC: "universal" view decorators
On Sep 16, 2011, at 11:42 AM, Łukasz Rekucki wrote: On 16 September 2011 10:17, Roald de Vries <downa...@gmail.com> wrote: On Sep 16, 2011, at 12:11 AM, Łukasz Rekucki wrote: I would like to also comment on the new approach in that ticket. Making a shallow copy of a class is *MAGIC* to me. It breaks the basic invariant "issubsclass(decorator(A), A) == True". This is important if you're planing to use this as "B = decorator()(A)" (and you are, 'cause the whole point of not modifying the original class is to allow safely doing this), as you quickly end up with weird alternate hierarchies. So, please don't do that :) I agree that in an ideal world we'd have a better solution. On the other hand, the cbv-decorator using inheritance just didn't work, and the one using shallow copies does (if you don't use B=decorator()(A), indeed). The one that just alters the given class also works, has no magic and has the same limitation - dont' do "B = decorator(A)". To show that this is actually a Python-thing, an analogous non- decorator-example: >>> class A(Base): ... def method(self, *args, **kwargs): ... super(A, self).method(*args, **kwargs) ... ... B = A ... A = SomeOtherClass ... ... B.method() Traceback (most recent call last): ... TypeError: unbound method method() must be called with A instance as first argument (got nothing instead) So IMHO it's "pythonic" to leave responsibility to use the decorator in the right way to the programmer. Cheers, Roald -- 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: RFC: "universal" view decorators
On Sep 16, 2011, at 10:08 AM, Jonathan Slenders wrote: class ProtectedView(MyView): login_required = True Where 'MyView' checks all the view's options during a dispatch. Never liked inheritance with multiple base classes... How would I create my own 'decorators' in this approach? Cheers, Roald -- 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: RFC: "universal" view decorators
Hi, On Sep 16, 2011, at 12:11 AM, Łukasz Rekucki wrote: Hi, On 15 September 2011 22:44, Jacob Kaplan-Mosswrote: #14512 proposes a adding another view-decorator-factory for decorating class-based views, which would turn the above into:: @class_view_decorator(login_required) class MyView(View): ... This makes me less sad, but still sad. Factory functions. Ugh. As the ticket creator I feel obligated to reply :) Me (as the poster of the latest patch) too :) Thinking about it now, it does look kinda ugly. It's mainly because I was focus on how to reuse existing decorators in CBV context. It shouldn't be to hard to make the "view_decorator" a meta-decorator (or a factory function as you call it) that turns login_required to something that is both a class and function decorator. Methods are still out-of-bounds for non-runtime introspection, but after almost 1 year of using CBV, I never needed to decorate a method. I would like to also comment on the new approach in that ticket. Making a shallow copy of a class is *MAGIC* to me. It breaks the basic invariant "issubsclass(decorator(A), A) == True". This is important if you're planing to use this as "B = decorator()(A)" (and you are, 'cause the whole point of not modifying the original class is to allow safely doing this), as you quickly end up with weird alternate hierarchies. So, please don't do that :) I agree that in an ideal world we'd have a better solution. On the other hand, the cbv-decorator using inheritance just didn't work, and the one using shallow copies does (if you don't use B=decorator()(A), indeed). As Donald mentioned, the more elegant solution for classes is to use base classes (mixins) instead of class decorators. I'm not sure though if every decorator can be replaced by a mixin, and if the order of these mixins can be arbitrary in that case (which I believe is desirable). Can anybody comment on that? I believe, however, I've figured out a different technique to make this work: don't try to detect bound versus unbound methods, but instead look for the HttpRequest object. It'll either be args[0] if the view's a function, or args[1] if the view's a method. This technique won't work for any old decorator, but it *will* work (I think) for any decorator *designed to be applied only to views*. +1 on this. I would be a bit concerned about this vs. future implementation of generator-based-views that allow some kind of response streaming (is someone working on that?). I've written a proof-of-concept patch to @login_required (well, @user_passes_test, actually): https://gist.github.com/1220375 Did I already mention creating a subclass in the class decorator breaks super ;) [https://gist.github.com/643536] Can I get some thoughts on this technique and some feedback on whether it's OK to apply to every decorator built into Django? It would be great to have that meta-decorator, so everyone else could upgrade their decorators just by decorating them. If this doesn't exist, then the view_decorator still has a right to live. So what would have to be created is a meta-decorator universal_decorator, replacing or using view_decorator, such that universal_decorator(login_required) is the actual universal decorator. This would be applied to all django-decorators, but I think it would be good to also allow applying universal_decorator to an already universal decorator, such that: # after this... login_required = universal_decorator(login_required) # ... this will hold assert login_required == universal_decorator(login_required) -- 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: class based views: object instead of dictionary as context?
On Sep 13, 2011, at 9:28 PM, Reinout van Rees wrote: On 13-09-11 20:33, Tobias McNulty wrote: I love it when problems solve themselves :-) That's a good point. Are there *any* methods in the CBVs that don't take arguments, that also modify data? The only one that I found in the list I'd initially proposed that can be called without arguments is as_view(), and I'm not sure that really even needs protection. Maybe there's no need to protect anything with alters_data / proxying? There's not really anything useful you can do with as_view in your template, should you attempt it. I also don't think you can do anything destructive with it. as_view() is a classonlymethod, which gives an AttributeError when called on an instance, so putting an instance of the cbv in the context seems fine for as far as this is concerned. -- 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: RFC: Templatetag API for form rendering - Second Edition
Hi Gregor, On the way home from DjangoCon I realized there is a (IMHO) elegant solution to this problem that is closer to the nature of django's template language. What you want with form-rendering is having defaults, but being able to override them; which is something you can do with django's templates. I think something like the following would be conceptually nice: # in some template {% with my_form as form %} {% include 'my_app/my_form.html' %} {% endwith %} # in templates/my_app/my_form.html {% extends 'form_as_table.html' %} {% block fieldblock %} {% ifequal field.name 'unnecessary_field' %} {# don't use this field #} {% else %} {{ block.super }} {% endifequal %} {% endblock %} # in templates/form_as_table.html {% block form %} {% block formerrors %} ...{# formerrors rendered #} {% endblock %} {% block fields %} {% for field in form.fields %} {% block field %} {% block label %}...{# label rendered #}{% endblock %} {% block fielderrors %}...{# fielderrors rendered #} {% endblock %} {% block widget %}...{# widged rendered #}{% endblock %} {% endblock %} {% endfor %} {% endblock %} {% endblock %} Now this is not ideal in a few ways; as far as I can see: 1) the form rendering has to be done in a separate file, because inheritance is needed 2) it would be more elegant if every field-block would have its own name Django's template language could be extended a little bit (?) to improve this: 1) block inheritance -- like a template can extend another template, a block could be able to extend another block or template: {% block form %} {% extends 'partial.html' %}{# or extendsblock block.super #} {% endblock form %} 2) dynamic block names -- like a template name in an {% extends %} tag can be either a string or a variable, the same could hold for the block name in a {% block %} tag (backward compatibility would have to be solved somehow; different tag name/extra argument/...). This would result in something like (for removing a field): {% with my_form as form %} {% block form %} {% extends 'form_as_table.html' %} {% dynamically_named_block 'unnecessary_field' %} {# overrides the field with nothing #} {% enddynamically_named_block %} {% endblock %} {% endwith %} Note that also the unnecessary_field-block can extend its base block. Choosing exactly which fields to render could be done like this: {% with my_form as form %} {% block form %} {% extends 'form_as_table.html' %} {% block fields %} {% for field_name in 'field1 field2 field3'|split %} {% dynamically_named_block field_name %} {{ block.super }}{# refers to the dynamically_named_block #} {% enddynamically_named_block %} {% endfor %} {% endblock fields %} {% endblock %} {% endwith %} Just brainstorming... let me know what you think. Cheers, Roald On Jun 3, 2011, at 4:58 PM, Gregor Müllegger wrote: Hi, this is the second RFC regarding template form rendering API/syntax. The first one defined how a complete form or a subset of fields will be rendered. I'm now proposing more tags to render more details like only the label of a form field. Currently we haven't discussed how we will substitute what we currently do with using:: {{ form.non_field_errors }} {{ form.errors }} {{ form.field.errors }} {{ form.field.help_text }} {{ form.field.label_tag }} We will implement these with template tags that are aware of the currently used layout: Substituting {{ \*.errors }}:: {% formerrors %} Some examples: Display *all* errors of a form:: {% formerrors my_form %} (equals current {{ my_form.errors }}) Non-field errors:: {% formerrors my_form.non_field_errors %} equals {{ my_form.non_field_errors }} Single-field errors:: {% formerrors my_form.firstname %} equals {{ my_form.firstname.errors }} Basically it will render the error list/dict that is available in the *errors* attribute of the passed in object. As an alternative (e.g. the non_field_errors) you can pass in directly a error list that gets rendered:: {% formerrors my_custom_error_list %} {% formerrors my_form.field.errors %} Substituting ``{{ form.field.label_tag }}`` This one might be pretty obvious:: {% formlabel my_form.field %} Substituting {{ form.field.help_text }} Also pretty obvious:: {% formhelp my_form.field %} But the naming is IMO not ideal. {% helptext %} as alternative is reasonable, but Carl and I agreed on that we wanted the tag to start with form* but {% formhelptext %} is to long. So we settled on {% formhelp %} Better suggestions are welcome. That's it basically. I don't see any
ForeignKey with null=True
Dear all, I have a model with a foreign key with null=True: class Many(Model): ForeignKey(One, null=True) class One(Model): pass Now if I do: one = One() ... then: one.many_set.all() ... returns all Many's with 'self.one_id == None'. From an implementational (SQL) standpoint, this seems logical, but from an OO standpoint, it surely doesn't. I would expect an empty queryset as a result, or maybe even some exception. Is the current behavior a (conscious) choice/feature, or a bug? Cheers, Roald -- 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.
Re: Feature request: ForeignKey through parameter
On Oct 28, 2010, at 4:02 PM, Javier Guerra Giraldez wrote: On Thu, Oct 28, 2010 at 2:54 AM, Roald de Vries <downa...@gmail.com> wrote: I quite often reference foreign keys of foreign keys of foreign keys... Wouldn't it be nice to have a 'through'-parameter for ForeignKey's? class A(Model): b = ForeignKey('B') c = ForeignKey('C', through='B', related_name='a_set') class B(Model): c = ForeignKey('C') i'd love such a feature too, but i think a better syntax could be something like: class A(Model): b = ForeignKey('B') c = ForeignKey('B__c', related_name='a_set') class B(Model): c = ForeignKey('C') where the second part of the reference is the name of the field ('c' in this example), not the model class ('C') On first sight, I think I agree with you that the syntax is cleaner like this, but I would choose for the through-parameter because it's more consistent with the use of the through-parameter for ManyToManyField. -- 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.
Feature request: ForeignKey through parameter
Dear all, I quite often reference foreign keys of foreign keys of foreign keys... Wouldn't it be nice to have a 'through'-parameter for ForeignKey's? class A(Model): b = ForeignKey('B') c = ForeignKey('C', through='B', related_name='a_set') class B(Model): c = ForeignKey('C') The advantages of a field A.c wrt a property A.c: - it creates a reverse relation, so C.a_set becomes available - c becomes queryable: A.objects.filter(c=x) For 'through'-ing one more class you could use: class Z(Model): a = ForeignKey('A') c = ForeignKey('C', through='A') # works because A.c exists or: class Z(Model): a = ForeignKey('A') c = ForeignKey('C', through='A__B') # works regardless of whether A.c exists I'm curious if other people would be interested in such a feature, or maybe if something alike or better already exists, and whether there are downsides that I miss. Cheers, Roald -- 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.
Re: #6735 -- Class based generic views: call for comment
Hi Ben, I like your implementation, but I don't really like the class name 'View'; I would opt for 'Resource' (or 'ResourceHandle'). Why I don't like 'View': - It's a very abstract thing, it's conceptually defined as 'the thing that maps a request to a response', or something alike - Instances of the class aren't actually views as they aren't callable - Consider 'MyView.as_view(*args, **kwargs)', which is weird Why I like 'Resource': - A resource is conceptually much clearer than a view (IMHO) - It conforms to standard naming: a URL addresses a resource - Methods like 'GET', 'POST', 'PUT', 'DELETE' make sense as attributes of a resource (handle) - django.resources is shorter than django.class_based_views ;-) I hope this makes sense, please let me know if it doesn't. Cheers, Roald On Oct 5, 2010, at 6:33 PM, Ben Firshman wrote: Thanks to everyone who's helping push this forward. I would get stuck in, but I'm bogged down with work at the moment. A couple of things from the wiki page that need doing: 1) Test coverage probably isn't great. Everything seems to work when I've used it in applications, but there's probably some stuff in there that isn't thoroughly tested. 2) Support for ModelForms isn't quite the same as our current generic views. For edit views, you can specify a model and the form is optional. Ben -- 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.