#35735 closed Bug (fixed)
For python 3.9+ class property may not be accessible by Django's template system — at Version 7
| Reported by: | Fabian Braun | Owned by: | Fabian Braun |
|---|---|---|---|
| Component: | Template system | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Fabian Braun | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Before python 3.9 class properties were always available through the template system. If you had a class
class MyClass(list):
in_template = True
do_not_call_in_templates = True # prevent instantiation
@classmethod
def render_all_objects(cls):
...
you could access the class property in the template through (if it was contained in the context) {{ MyClass.in_template }} or {{ MyClass. render_all_objects }}.
The template system first gets the class MyClass (and does not instantiate it) or gets it as a result of a callable get_my_class. Then it checks if the class is subscriptable (i.e. tries MyClass["in_template"]), will fail and then will get the in_template property.
As of python 3.9 some classes actually are subscriptable and trying to get the item will not fail: Typing shortcuts introduced syntax like list[int]. These hide class properties or methods from the template system.
Here's a test (that might go into tests/template_tests/syntax_tests/tests_basic.py) which passes on Python 3.9 and fails on Python 3.10+:
@setup({"basic-syntax19b": "{{ klass.in_template }}"})
def test_access_class_property(self):
class MyClass(list):
in_template = True
do_not_call_in_templates = True # prevent instantiation
output = self.engine.render_to_string("basic-syntax19b", {"klass": MyClass})
self.assertEqual(output, "True")
I'd be happy to propose a fix that will not call a classes' __class_getitem__ method.
Thanks to Ben Stähli and Serhii Tereshchenko for figuring out this issue.
References:
Change History (7)
comment:1 by , 14 months ago
| Description: | modified (diff) |
|---|---|
| Owner: | set to |
| Status: | new → assigned |
comment:2 by , 14 months ago
| Description: | modified (diff) |
|---|---|
| Summary: | For python 3.10+ class property may not be accessible by Django's template system → For python 3.9+ class property may not be accessible by Django's template system |
| Type: | Uncategorized → Bug |
comment:3 by , 14 months ago
| Description: | modified (diff) |
|---|---|
| Has patch: | set |
comment:4 by , 14 months ago
| Description: | modified (diff) |
|---|
comment:5 by , 14 months ago
comment:6 by , 14 months ago
| Resolution: | → needsinfo |
|---|---|
| Status: | assigned → closed |
| Version: | 5.0 → dev |
comment:7 by , 14 months ago
| Description: | modified (diff) |
|---|
Hi Fabian, thank you for taking the time to create this report!
(Before your last edit) I have tried to reproduce the issue described and I wasn't able to, I then analyzed your test and noticed that in the test (but not in the ticket description)
MyClassis a child oflist. For that case, and for children ofdictorset, the test indeed fail; but for children ofobject,str,int, the test do not fail.So on one hand, the issues seems less generic than presented in the title and description. On the other hand, I'm not sure what you mean with:
My first thought is that your
MyClassis subscriptable because it's a child oflist... so I'm having a hard time understanding how Django is at fault here. Could you please elaborate?Also for this sentence:
I have grepped all the Django source code and nothing other than a few classes in the ORM implement
__class_getitem__, so what do you mean exactly?I'm closing as
needsinfobut please reopen when you can provide further clarifications. Thanks again!