Bold text with asterisks - python

In my Django project I want to make text bold if asterisks * are there at the start and end of text, the same feature we have here on Stack Overflow. Although I convert ** to <b>, due to output escaping it becomes <b>. What is the right approach to achieve this?
template file contains {{ anidea.description|format_text}}
format_text is custom template filter
code..
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#register.filter(name='format_text')
def custom_formating(value):
for word in value.split():
start = word[:2]
end = word[-2:]
if start == '**' and end == '**':
word = word[2:-2]
word = '<b>' +word+ '</b>'
mark_safe(word)
return value

if you want the full suite of all markdown features, go with an existing markdown library.
if you just want <b> to print directly to the source code w/o escaping, use
{{ some_var|safe }}

I did it in following way.
views.py
i.description = i.description.split() #use of split()
template file (format_text is custom template filter)
{% for text in anidea.description %}
{{ text|format_text }}
{% endfor %}
filter
#register.filter(name='format_text')
def custom_formating(value):
start = value[:2]
end = value[-2:]
if start == '**' and end == '**':
value = value[2:-2]
value = '<b>' +value+ '</b>'
return mark_safe(value)
else:
return value
with this way I can achieve output escaping for description and desired text formatting.

Related

Flask: Python List is displaying values in HTML file with quote marks and round brackets

I have the below function which returns a list
def get_entered_datalist(firstname, lastname):
if firstname and lastname:
curr = db.session.execute(entered_data, {'firstname': firstname, 'lastname': lastname})
list_name = list() #this is a list contstructor statement so have () brackets, usually when declaring list we use [] brackets
for name in curr:
list_name.append(name)
return list_name
else:
return False
It is being called this way
entered_names = get_entered_datalist(session['v_firstname'], session['v_lastname'])
and passed to the html file this way
return render_template('monthlybudget.html', title='Enter Monthly Budget Data', form=form, entereddata=entered_names)
The display code in HTML file is as below
{% if entereddata %}
{% for x in entereddata %}
<p>{{ x }} </p>
{% endfor %}
{% else %}
<p>No data found</p>
{% endif %}
but it is being displayed with round brackets and quote marks as below
The query getting the values from database is as below
select concat([First Name], ' ', [Last Name] ) as name from [dbo].[EAMonthlyBudget]
where [Report to First Name]= :firstname and [Report to Last Name] = :lastname
and [budget month] = datename(month,getdate()) and [budget year] = year(getdate());
I added a print statement in my python code to check what gets returned by the function and that is as below (shows with the brackets and quote marks)
[12/Aug/2022 15:29:44] "GET /static/images/nu_logo2.png HTTP/1.1" 304 -
[('Janak Shah',), ('Julie Wang',)]
-
How do I display the data without the brackets and quote marks?
Your curr variable contains tuples. try this code:
for name in curr:
list_name.append(name[0])
I think you need to check of index out for range error.
I hope this helps.

Passing list dict to template not working django

I am trying to pass a list called eligable so that I can display on my website but when I run my website it does not display the list. I do not understand what is wrong.
code:
def specificDate(response):
empName = employeeName.objects.all()
eligable = []
if 'checkEmployee' in response.POST:
n = response.POST.get("nameEmployee")
specDate = response.POST.get("date")
if employeeName.objects.filter(employee=n).exists() and Name.objects.filter(date=specDate).exists():
emp = employeeName.objects.get(employee=n)
t = Name.objects.get(name=emp, date=specDate)
overT = Name.objects.filter(name=emp, overtime=True)
for item in overT:
eligable.append(item.date)
checkIn = t.timeIn.strftime("%H:%M:%S")
checkOut = t.timeOut.strftime("%H:%M:%S")
datee = datetime.strptime(specDate,'%Y-%m-%d')
print("Here:: ",t.date)
print("Month:: ",datee.month)
messages.info(response, checkIn + ' - ' + checkOut)
return redirect('/specificDate')
else:
messages.info(response, 'Name does not exist')
else:
pass
return render(response, "main/specificDate.html", context={"empName":empName, "eligable":eligable})
This is the html to print my list:
{% for item in eligable %}
<div class="pad3">
{{item}}
</div>
{% endfor %}
There are two return statements in your code:
return redirect('/specificDate')
and
return render(response, "main/specificDate.html", context={"empName":empName, "eligable":eligable})
The first one is just redirecting without populating context.
The second one does populate context but is reached only when eligable is empty.
I think changing the first return to the second one should solve it.
edit: and you are missing {% endfor %} here. But it should give you an error if you miss it in your complete code.

Highlight exact phrase with haystack/elasticsearch in Django

My web app uses Django Haystack with Elasticsearch as the search engine.
My SearchForm child class filters for exact search (content__exact parameter) if the search query contains a token with quotes.
class NepSearchForm(SearchForm):
# ...
def search(self):
if not self.is_valid():
return self.no_query_found()
if not self.cleaned_data.get('q'):
return self.no_query_found()
sqs = self._parse_query(self.cleaned_data['q'])
if self.load_all:
sqs = sqs.load_all()
return sqs
def no_query_found(self):
return self.searchqueryset.all()
def _parse_query(self, query):
"""
Parse query treating modifiers 'AND', 'OR', 'NOT' to make what they're
supposed to.
:param query: query entered in search input box in form
:param sqs: SearchQuerySet until now
:return: SearchQuerySet object
"""
words = iter(shlex.split(query))
result = self.searchqueryset
for word in words:
try:
if word == 'AND':
result = result.filter_and(content=words.__next__())
elif word == 'OR':
# TODO: fail when changing order of the words. See
# TODO: functional test:
# TODO: test_search_with_OR_modifier_returns_correct_objects
result = result.filter_or(content=words.__next__())
elif word == 'NOT':
result = result.exclude(content=words.__next__())
# if "word" is compounded of more than one non blank word the
# term is inside quotes
elif len(word.split()) > 1:
result = result.filter(content__exact=word)
else:
result = result.filter(content=word)
except StopIteration:
return result
return result
I'm using the Django template tag {% highlight %} to highlight the terms searched in my app, like in:
{% highlight result.object.<field> with query %}
What I'm seeing is that, when I make a search with quotes with more than one word, separated by spaces, e.g "História de fratura", the search results appears with only the token "de" highlighted. So it seems that Highlighter class does not treat terms with quotes as single tokens to mark them highlighted in search results.
What can I do to highlight the query with a whole term inside quotes in search results?
You can build your own highlighter class as documentation states if default highlighter implementation doesn't work for you.

Jinja2 filter to convert custom markup to html

Having the autoescape property on (I want to keep it that way), I want user to be able to enter some custom markup, to have the opportunity to format text. For example, [s][/s] will be translated into <strong></strong>. I believe the right way to do this is to write the custom Jinja2 filter. But the following doesn't work:
#app.template_filter()
#evalcontextfilter
def mark2html(eval_ctx, value):
result = escape(value).replace('[s]','<strong>')
if eval_ctx.autoescape:
result = Markup(result)
return result
When applied to text like
<div>{{ custom_markup_text|mark2html }}</div>
When [s] is encountered in the string, stored in custom_markup_text, it should be converted to <strong> tag. AFAIK, Markup() function ensures that we trust this particular string, so that HTML is not escaped there. The filter is successfully applied, [s] is replaced by <strong>, but it's still escaped.
Obviously, the autoescaping is done after this custom filter. On the other hand, example filter from Jinja2 documentation works perfectly:
#app.template_filter()
#evalcontextfilter
def nl2br(eval_ctx, value):
result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n') \
for p in _paragraph_re.split(escape(value)))
if eval_ctx.autoescape:
result = Markup(result)
return result
What am I doing wrong?
Problem found. It's double escaping the string - rather silly.
This code works flawlessly:
#app.template_filter()
#evalcontextfilter
def mark2html(eval_ctx, value):
result = value.replace('[s]',u'<strong>')
result = result.replace('[/s]',u'</strong>')
if eval_ctx.autoescape:
result = Markup(result)
return result
Note, value shouldn't be escaped, as autoescape property is on.

Replacing text with variables

I have to send out letters to certain clients and I have a standard letter that I need to use. I want to replace some of the text inside the body of the message with variables.
Here is my maturity_letter models.py
class MaturityLetter(models.Model):
default = models.BooleanField(default=False, blank=True)
body = models.TextField(blank=True)
footer = models.TextField(blank=True)
Now the body has a value of this:
Dear [primary-firstname],
AN IMPORTANT REMINDER…
You have a [product] that is maturing on [maturity_date] with [financial institution].
etc
Now I would like to replace everything in brackets with my template variables.
This is what I have in my views.py so far:
context = {}
if request.POST:
start_form = MaturityLetterSetupForm(request.POST)
if start_form.is_valid():
agent = request.session['agent']
start_date = start_form.cleaned_data['start_date']
end_date = start_form.cleaned_data['end_date']
investments = Investment.objects.all().filter(maturity_date__range=(start_date, end_date), plan__profile__agent=agent).order_by('maturity_date')
inv_form = MaturityLetterInvestments(investments, request.POST)
if inv_form.is_valid():
sel_inv = inv_form.cleaned_data['investments']
context['sel_inv'] = sel_inv
maturity_letter = MaturityLetter.objects.get(id=1)
context['mat_letter'] = maturity_letter
context['inv_form'] = inv_form
context['agent'] = agent
context['show_report'] = True
Now if I loop through the sel_inv I get access to sel_inv.maturity_date, etc but I am lost in how to replace the text.
On my template, all I have so far is:
{% if show_letter %}
{{ mat_letter.body }} <br/>
{{ mat_letter.footer }}
{% endif %}
Much appreciated.
use format strings:
>>> print "today is %(date)s, im %(age)d years old!" % {"date":"my birthday!","age":100}
today is my birthday!, im 100 years old!
I think this is the best way to do it. First, you have a file with your template, something like:
Dear {{primary-firstname}},
AN IMPORTANT REMINDER…
You have a {{product}} that is maturing on {{maturity_date}} with {{financial institution}}.
etc ...
So, your view will go something like:
from django.template.loader import render_to_string
# previous code ...
template_file = 'where/is/my/template.txt'
context_data = {'primary-firstname': 'Mr. Johnson',
'product': 'banana',
'maturity_date': '11-17-2011',
'financial institution': 'something else'}
message = render_to_string(template_file, context_data)
# here you send the message to the user ...
So if you print message you'll get:
Dear Mr. Johnson,
AN IMPORTANT REMINDER…
You have a banana that is maturing on 11-17-2011 with something else.
etc ...
One solution is to use Django's template engine on the body itself (as you do when rendering the page). I am sure there are security implications if the text is editable by users etc.
A simpler solution would be simple string replacement. For example, given what you have above:
for var, value in sel_inv.items:
body = body.replace('[%s]' % var, value)
It's not the prettiest solution, but if your body template is fixed you need to do something like this.
You can use regular expression substitution with a callback. The advantage of this over a simple string replace or using django's template engine is that you also know when undefined variables are used (since you might not want to send out letters/emails like that :)
import re
body = """
Dear [primary-firstname],
AN IMPORTANT REMINDER...
You have a [product] that is maturing on [maturity_date]
with [financial institution].
etc
"""
def replace_cb(m):
replacements = {'primary-firstname': 'Gary',
'product': 'Awesome-o-tron2k',
'maturity_date': '1-1-2012',
'financial institution': 'The bank'}
r = replacements.get(m.groups()[0])
if not r:
raise Exception('Unknown variable')
return r
new_body = re.sub('\[([a-zA-Z-_ ]+)\]', replace_cb, body)

Categories