Django templates are significantly different than all the other ones you mentioned.
It was architected from the beginning to be friendly to non-programmers -- the idea was that someone writing an article for the Lawrence Journal-World (or a designer) could easily use custom templating in a constrained templating language that developers can augment with custom tags and filters.
It surprisingly works incredibly well for that use case. The templating language strictly enforces view-separation -- the template author can't do anything the developer didn't intentionally let them do.
It can be ridiculously frustrating if you're expecting it to be a normal language -- for instance __getitem__, __getattr__, and __call__ all use the same "obj.property: arg" syntax. It calls hasattr at every call site to figure this out, and you can't use () or [] even if you wanted to. Fuck, you can't pass multiple arguments to a function!
It was architected from the beginning to be friendly to non-programmers -- the idea was that someone writing an article for the Lawrence Journal-World (or a designer) could easily use custom templating in a constrained templating language that developers can augment with custom tags and filters.
It surprisingly works incredibly well for that use case. The templating language strictly enforces view-separation -- the template author can't do anything the developer didn't intentionally let them do.
It can be ridiculously frustrating if you're expecting it to be a normal language -- for instance __getitem__, __getattr__, and __call__ all use the same "obj.property: arg" syntax. It calls hasattr at every call site to figure this out, and you can't use () or [] even if you wanted to. Fuck, you can't pass multiple arguments to a function!