Hindi or Farsi numbers in django templating engine - python

I want to print {{forloop.counter}} with persian or Hindi encoding means to have "۱ ۲ ۳ ۴ .." instead of "1 2 3 4 ...". I searched a lot but I couldn't find any related functions. Would you mind helping me?
Regards

You could use a custom template filter. I'm not familiar enough with Django's l10n library to know if they do this for you.
def devanagari_int(arabic_int):
""" Converts an arabic numeral (ex. 5817) to Devanagari (ex. ५८१७) """
devanagari_nums = ('०','१','२','३','४','५','६','७','८','९')
# arabic_nums = ('۰','١','۲'....)
# farsi_nums = (...)
number = str(arabic_int)
return ''.join(devanagari_nums[int(digit)] for digit in number)
# register your filter, and then:
{{forloop.counter|devanagari_int}}
Make sure you save your filter file as UTF-8 (or instead use the appropriate unicode representations).

You can create your own template filter.
#register.filter(name='persian_int')
def persian_int(english_int):
devanagari_nums = ('۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹')
number = str(english_int)
return ''.join(devanagari_nums[int(digit)] for digit in number)
#register.filter(name='hindi_int')
def hindi_int(english_int):
devanagari_nums = ('०','१','२','३','४','५','६','७','८','९')
number = str(english_int)
return ''.join(devanagari_nums[int(digit)] for digit in number)

You could make a templatefilter that converts a number to the appropriate encoding. You could then use it as such:
{{ forloop.counter|convert_to_hindi }}

You can use the django internationalization there is a library l10n is define in django

You can create your own custom template tag.
To do so you need to create the following files assuming your app is called "myapp"
myapp/
__init__.py
models.py
templatetags/
__init__.py
extra_tags.py
views.py
Then add the following code in the file extra_tags.py
from django import template
register = template.Library()
#register.filter(name='persianize_digits')
def persian_int(string):
persianize = dict(zip("0123456789",'۰۱۲۳۴۵۶۷۸۹'))
return ''.join(persianize[digit] if digit in persianize else digit for digit in str(string))
Now you can simply do {{ value|persianize_digits }} in your templates and the digits will become Persian. This method also works for strings that are not numbers as a whole but include some digits in them, e.g. 10:27:33 which is a time duration.

You might try the unicode version of template filter as follows:
register = template.Library()
to_arabic_number_trans = dict(
zip((ord(s) for s in u'0123456789'),
u'\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669')
)
to_english_number_trans = dict(
zip((ord(s) for s in u'٠١٢٣٤٥٦٧٨٩'),
u'\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089')
)
#register.filter
def format_number(value):
cur_lang = get_language()
if hasattr(value, 'translate'):
if cur_lang == 'ar':
return value.translate(to_arabic_number_trans)
return value.translate(to_english_number_trans)
return value
This works well for stand alone numbers, however any ideas about numbers in date?
like in
2 يونيو، 2020
how can i get it right without messing with datetime objects!

This worked for me to turn english numbers to persian numbers
from django import template
register = template.Library()
#register.filter(name='persian_int')
def persian_int(english_int):
persian_nums = {'0':'۰', '1':'۱', '2':'۲', '3':'۳', '4':'۴', '5':'۵', '6':'۶', '7':'۷', '8':'۸', '9':'۹'}
number = str(english_int)
persian_dict = number.maketrans(persian_nums)
result = number.translate(persian_dict)
return result

Related

Objects.filter(" ı wanna add two contains field")

This is search field. But in the views ı cant search on two field. I tried all of this. its not working.
its only working in one fields like = Makale.objects.filter(baslik__contains=keyword)
makale = Makale.objects.filter(baslik__contains=keyword,icerik_contains=keyword)
makale = Makale.objects.filter(baslik_contains=keyword or icerik_contains=keyword)
def paylasimlar(request):
keyword = request.GET.get("keyword")
if keyword:
paylasimlar = Makale.objects.filter(icerik__contains=keyword)
return render(request, "feed.html", {"paylasimlar": paylasimlar})
paylasimlar = Makale.objects.all()
return render(request, "feed.html", {"paylasimlar":paylasimlar})
You can add an or operator between two constraints by using Q-objects [Django-doc] and the or (|) operator [Django-doc], like:
from django.db.models import Q
Makale.objects.filter(Q(baslik__contains=keyword) | Q(icerik__contains=keyword))

Django CursorPagination for ordering by several fields

I am using Django DRF's CursorPagination for lazy loading of my data, and currently my goal is to sort the data by more than one field.
This is how my code looks like now:
class EndlessPagination(CursorPagination):
ordering_param = ''
def set_ordering_param(self, request):
self.ordering = request.query_params.get(self.ordering_param, None)
if not self.ordering:
raise ValueError('Url must contain a parameter named ' +
self.ordering_param)
if self.ordering.startswith("\"") or self.ordering.endswith("\""):
raise ValueError('Ordering parameter should not include quotation marks'
def paginate_queryset(self, queryset, request, view=None):
# This function is designed to set sorting param right in the URL
self.set_ordering_param(request)
return super(EndlessPagination, self).paginate_queryset(queryset, request, view)
This code works fine for urls like my_url/sms/270380?order_by=-timestamp, but what if I want to sort by several fields ?
Use str.split() to split the url params
class EndlessPagination(CursorPagination):
ordering_param = 'order_by'
def set_ordering_param(self, request):
ordering_param_list = request.query_params.get(self.ordering_param, None)
self.ordering = ordering_param_list.split(',')
# here, "self.ordering" will be a "list", so, you should update the validation logic
"""
if not self.ordering:
raise ValueError('Url must contain a parameter named ' +
self.ordering_param)
if self.ordering.startswith("\"") or self.ordering.endswith("\""):
raise ValueError('Ordering parameter should not include quotation marks'
"""
def paginate_queryset(self, queryset, request, view=None):
# This function is designed to set sorting param right in the URL
self.set_ordering_param(request)
return super(EndlessPagination, self).paginate_queryset(queryset, request, view)
Example URLs
1. my_url/sms/270380?order_by=-timestamp
2. my_url/sms/270380?order_by=-timestamp,name
3. my_url/sms/270380?order_by=-name,foo,-bar
UPDATE-1
First of all thanks to you for giving a chance to dig deep :)
As you said, me too didn't see comma seperated query_params in popular APIs. So, Change the url format to something like,my_url/sms/270380??order_by=-name&order_by=foo&order_by=-bar
At this time, the request.query_params['order_by'] will be a list equal to ['-name','foo','-bar']. So, you don't want to use the split() function, hence your set_ordering_param() method become,
def set_ordering_param(self, request):
self.ordering = request.query_params.get(self.ordering_param, None)
#...... your other validations

Does django's URL Conf support mapping an argument to strings?

The Problem
I'm unsure of the best way to phrase this, but here goes: (note some of this may not be syntactically/semantically correct, as it's not my actual code, but I needed it to help explain what I'm asking)
Say I have a model the model Album:
Class Album(models.Model):
ALBUM_TYPE_SINGLE = 1
ALBUM_TYPE_DEMO = 2
ALBUM_TYPE_GREATEST_HITS = 3
ALBUM_CHOICES = (
(ALBUM_TYPE_SINGLE, 'Single Record'),
(ALBUM_TYPE_DEMO, 'Demo Album'),
(ALBUM_TYPE_GREATEST_HITS, 'Greatest Hits'),
)
album_type = models.IntegerField(choices=ALBUM_CHOICES)
And I want to have separate URLs for the various types of albums. Currently, the URL Conf is something like so:
urlpatterns = [
url(r'^singles/(?P<pk>.+)/$', views.AlbumView, name="singles"),
url(r'^demos/(?P<pk>.+)/$', views.AlbumView, name="demos"),
url(r'^greatest-hits/(?P<pk>.+)/$', views.AlbumView, name="greatest_hits"),
]
And when I want to serve the appropriate URL, I need to check the album_type manually:
if object.album_type == Album.ALBUM_TYPE_SINGLE:
return reverse('singles', object.id)
elif object.album_type == Album.ALBUM_TYPE_DEMO:
return reverse('demos', object.id)
elif object.album_type == Album.ALBUM_TYPE_GREATEST_HITS:
return reverse('greatest_hits', object.id)
However, this is cumbersome to do, and I'm wondering if there is a way to pass in the album_type field to the call to reverse and have it automatically get the URL based on that. i.e. something like this:
urlpatterns = [
url(r'^(?P<type>[singles|demos|greatest-hits])/(?P<pk>.+)/$', views.AlbumView, name="albums"),
]
and called with
reverse("albums", object.album_type, object.id)
Attempted solutions
I considered setting the choice strings to be
ALBUM_CHOICES = (
(ALBUM_TYPE_SINGLE, 'singles'),
(ALBUM_TYPE_DEMO, 'demos'),
(ALBUM_TYPE_GREATEST_HITS, 'greatest-hits'),
)
which would then allow me to send object.get_album_type_display() as a string variable for type, which works, however, I need to be able to use reverse to build the URL while only having access to the integer value of album_type and not the display value.
I know this is an oddly specific question for an oddly specific scenario, but if anyone has any kind of potential solutions, I'd be very grateful! Thank you in advance!
I would change the field to a CharField, and use the URL slug as the actual value rather than the display value:
Class Album(models.Model):
ALBUM_TYPE_SINGLE = 'singles'
ALBUM_TYPE_DEMO = 'demos'
ALBUM_TYPE_GREATEST_HITS = 'greatest-hits'
ALBUM_CHOICES = (
(ALBUM_TYPE_SINGLE, 'Single Record'),
(ALBUM_TYPE_DEMO, 'Demo Album'),
(ALBUM_TYPE_GREATEST_HITS, 'Greatest Hits'),
)
album_type = models.CharField(choices=ALBUM_CHOICES, max_length=50)
In your urls.py:
urlpatterns = [
url(r'^(?P<type>singles|demos|greatest-hits)/(?P<pk>.+)/$', views.AlbumView, name="albums"),
]
Then you can reverse it by passing album.album_type:
reverse('albums', args=(album.album_type, album.pk))

displaying unique objects only in django templates

I have a list of objects. I want to display these objects in such a way that only the first unique date displays if the subsequent objects contain the same date. If the date is different than it should display. Here is an example.
data:
id: 2, date: "01/01/2010"
id: 3, date: "01/01/2010"
id: 4, date: "02/02/2010"
What I want to display:
id - 2, "01/01/2010"
id - 3,
id - 4, "02/02/2010"
See how id 3 shows nothing since the previous date was the same?
How do I do this with django templates? One thing I tried was creating a custom filter. The only problem is that it uses a global variable which is a no-no in my opinion. How can I maintain state in a function filter or in django templating language to be concious of the previous value?
__author__ = 'Dave'
#This works but isn't best practice
from django import template
register = template.Library()
a = ''
#register.filter()
def ensure_unique(value):
global a
if a == value:
return ''
else:
a = value
return value
Using a simple_tag made it much easier for me to save state and accomplish exactly what I needed to.
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def stop_repeat(context, event):
"""
Finds various types of links embedded in feed text and creates links out of them.
"""
if event.date:
if (event.get_date_time_location(), event.id) in context:
return ''
else:
context[(event.get_date_time_location(), event.id)] = (event.get_date_time_location(), event.id)
return event.get_date_time_location()

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