There should be a way to make Templates substitution to raise an exception on error

143 views
Skip to first unread message

Shreyas Pandya

unread,
Sep 21, 2017, 7:05:28 AM9/21/17
to Django developers (Contributions to Django itself)
Hi All,

What is your opinion on having an option to raise an error in template if variable is not found in context. This may be useful for automated  tests as discussed in ticket. 

reference ticket #28618 ; 

Thanks

regards
Shreyas

Zhiqiang Liu

unread,
Sep 21, 2017, 9:35:05 AM9/21/17
to Django developers (Contributions to Django itself)
This is not 100% related to the ticket, but something to think about.

In ReactJS, there a concept called propTypes, which will check all props (they are similar to context in concept I think) listed with types in UI component.

So maybe we can have something similar in django template system that a template can have an attribute called contextTypes and it can be a dict of context the template may have. It doesn't need to have all possible context values, only include those you want to make sure the context are passed and value types are correct.

A simple example can be


contextTypes = {
   
"name": contextTypes.string.isRequired,

}



Zhiqiang Liu

unread,
Sep 21, 2017, 9:37:48 AM9/21/17
to Django developers (Contributions to Django itself)
To continue the previous comment.

template can raise error give warning if required contexts are not provided or the types are not correct. You can have something not isRequired in contextTypes too but types can be check if the context is actually passed to template.

Tom Forbes

unread,
Sep 21, 2017, 9:46:37 AM9/21/17
to django-d...@googlegroups.com
You could perhaps emulate something like that with a template tag, couldn't you?

@register.simple_tag(takes_context=True)
def requires(context, *names):
    for name in names:   
        if name not in context:
            raise RuntimeError('{0} is not in the template context'.format(name))

And in the template:

{% requires "name" "other" %}

Seems that it would be best if that kind of data lived with the template, rather than outside in a Python file.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/0e82ce82-3a0d-44a6-9f68-f359a7354eb9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tom Forbes

unread,
Sep 21, 2017, 9:51:43 AM9/21/17
to django-d...@googlegroups.com
You could perhaps emulate that with a template tag, it seems it would be best if this was kept in the template rather than in some associated Python file:

@register.simple_tag(takes_context=True)
def requires(context, *names):
    for name in names:
        if name not in context:
            raise RuntimeError('Missing context: {0}'.format(name))

{% requires "name" "other" %}

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

Emil Stenström

unread,
Sep 22, 2017, 2:10:16 AM9/22/17
to Django developers (Contributions to Django itself)
It as actually possible, just in a very hacky way. Django has a setting called TEMPLATE_STRING_IF_INVALID (or TEMPLATES[0]["OPTIONS"]["string_if_invalid"] in current versions of Django). If you override it and set it to a class with a __str__ that raises an exception you can get the effect you want. We use this in tests to find missing variables quickly.

Reference code: https://djangosnippets.org/snippets/646/

Adam Johnson

unread,
Sep 22, 2017, 5:00:00 AM9/22/17
to django-d...@googlegroups.com
I've used a solution like the one Emil links to before to great success, though perhaps there's scope to make it a bit less hacky in Django.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.

For more options, visit https://groups.google.com/d/optout.



--
Adam

Sjoerd Job Postmus

unread,
Sep 22, 2017, 6:14:38 AM9/22/17
to Django developers (Contributions to Django itself)
Indeed it could be!

What if it was not `string_if_invalid` but `if_invalid`. The value could be:

* An Exception instance (which would then be raised)
* An Exception class (which would be instantiated with the "invalid" thing), and then be raised
* A callable (which would be called, and must return a string or raise), and the result used (unless it raises an exception, in which case that exception is propogated upwards)
* A string (which would be interpolated with `%` if it contains "%s") to be used instead.

(in that order).

We also use the `string_if_invalid` trick with a custom class that provides `__mod__`/`__contains__`. Would be great if we could handle that at the Django layer.


On Friday, September 22, 2017 at 11:00:00 AM UTC+2, Adam Johnson wrote:
I've used a solution like the one Emil links to before to great success, though perhaps there's scope to make it a bit less hacky in Django.
On 22 September 2017 at 07:10, Emil Stenström <e...@kth.se> wrote:
It as actually possible, just in a very hacky way. Django has a setting called TEMPLATE_STRING_IF_INVALID (or TEMPLATES[0]["OPTIONS"]["string_if_invalid"] in current versions of Django). If you override it and set it to a class with a __str__ that raises an exception you can get the effect you want. We use this in tests to find missing variables quickly.

Reference code: https://djangosnippets.org/snippets/646/

On Thursday, 21 September 2017 13:05:28 UTC+2, Shreyas Pandya wrote:
Hi All,

What is your opinion on having an option to raise an error in template if variable is not found in context. This may be useful for automated  tests as discussed in ticket. 

reference ticket #28618 ; 

Thanks

regards
Shreyas

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.



--
Adam

pandyas...@gmail.com

unread,
Sep 27, 2017, 10:55:32 AM9/27/17
to Django developers (Contributions to Django itself)
Please find comment inline

On Friday, 22 September 2017 15:44:38 UTC+5:30, Sjoerd Job Postmus wrote:
Indeed it could be!

What if it was not `string_if_invalid` but `if_invalid`. The value could be:

* An Exception instance (which would then be raised)
* An Exception class (which would be instantiated with the "invalid" thing), and then be raised
* A callable (which would be called, and must return a string or raise), and the result used (unless it raises an exception, in which case that exception is propogated upwards)
* A string (which would be interpolated with `%` if it contains "%s") to be used instead.
This seems like an overkill. What if we instead provide an additional boolean flag `raise_if_invalid`

Sjoerd Job Postmus

unread,
Sep 27, 2017, 11:40:19 AM9/27/17
to Django developers (Contributions to Django itself)
Also: inline.


On Wednesday, September 27, 2017 at 4:55:32 PM UTC+2, pandyas...@gmail.com wrote:
Please find comment inline

On Friday, 22 September 2017 15:44:38 UTC+5:30, Sjoerd Job Postmus wrote:
Indeed it could be!

What if it was not `string_if_invalid` but `if_invalid`. The value could be:

* An Exception instance (which would then be raised)
* An Exception class (which would be instantiated with the "invalid" thing), and then be raised
* A callable (which would be called, and must return a string or raise), and the result used (unless it raises an exception, in which case that exception is propogated upwards)
* A string (which would be interpolated with `%` if it contains "%s") to be used instead.
This seems like an overkill. What if we instead provide an additional boolean flag `raise_if_invalid`

I do agree that the above specification seems overkill. However, I think that a boolean flag `raise_if_invalid` is the wrong approach: One could have both `string_if_invalid` defined and `raise_if_invalid` (and will we also add `log_if_invalid`?).

For simplicity, having an `if_invalid` that is a callable that either returns a string (or raises an exception) seems to be the most generic approach. For Django it's "always call the function" (the default simply would be `return ''`). One can add all the logic one wants into that specific function: raising exceptions, logging, returning a string (like `string_if_invalid`?)

All the other options (Exception instances and classes and strings) are indeed overkill (it can be handled by that function I mentioned), but would allow for a simpler `settings.py`.
Reply all
Reply to author
Forward
0 new messages