Reputation: 129
I'm working on configurable email template and need to validate if only available_variables
are used in the content. So if user put {{ apple }}
, the form should return ValidationError('This variable is unavailable')
.
models.py:
email_content = models.TextField()
forms.py:
def clean_email_content(self):
email_content = self.cleaned_data['email_content']
available_variables = ['{{ company_name }}', '{{ user_name }}']
required_variables = ['{{ company_name }}']
for required_variable in required_variables:
if not required_variable in email_content:
raise forms.ValidationError("{} is required".format(required_variable))
# how to check if there are only `available_variables` in the content?
TL;DR
email_content
cannot contain other variables (strings that starts with {{
and ends with }}
) than specified in available_variables
Should I use regex or can I validate this using some method from Django Template Engine?
Upvotes: 2
Views: 483
Reputation: 77912
You may want to use the template engine's lexer instead (nb: django 1.11 code, might need to be adapted if you use django 2.x):
from django.template import base
lexer = base.Lexer("{{ var_one }} is one {% if var_two %}{{ var_two|upper }} is two {% endif %}")
tokens = lexer.tokenize()
for t in tokens:
if t.token_type == base.TOKEN_VAR:
print("{}: {}".format(t, t.contents)
I leave it up to you to read the template.base code to find out other useful features...
Also in your validation method you definitly want to catch ALL errors at once (instead of raising as soon as you found an error) so the user can fix all errors at once (unless you really want to drive your users mad, that is).
And finally, as Gasanov suggests in his answer, you also want to use sets to find both missing required vars and illegal ones - this is much more efficient than doing sequential lookups.
Upvotes: 3
Reputation: 3399
We can use regex to find all tags from email_content
. After that we convert them to set
and substract all available_variables
from it to find all incorrect ones. If any exists - we throw ValidationError
.
Note that available_variables
is set
itself and contains just tags, without curly brackets.
Our regex checks for any numbers of spaces between brackets and tag, so your users shouldn't be able to cheat.
import re
def clean_email_content(self):
email_content = self.cleaned_data['email_content']
available_variables = {'company_name', 'user_name'}
finds = re.findall(r"{{[ ]*(.*?)[ ]*}}", email_content)
invalid_tags = set(finds) - available_variables
if invalid_tags:
raise forms.ValidationError(
"Should not contain invalid tags: " + str(invalid_tags)
)
return email_content
Upvotes: 1