--
Ticket URL: <https://code.djangoproject.com/ticket/17662>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* cc: anssi.kaariainen@… (added)
* needs_docs: => 0
* needs_better_patch: => 1
* needs_tests: => 0
* stage: Unreviewed => Accepted
Comment:
I am in general in support of this, as I can see the need for this common
enough to include in Django.
I wonder if you should use decimal.Decimal instead to get proper rounding.
If I am not mistaken the string formatting just truncates the value. I
will mark the patch as needs improvement for that reason.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:1>
Comment (by eire1130):
I believe str.format("{':.places%'}") rounds "correctly", example:
>>>myfloat= .56784
>>>print "{:.2%}".format(myfloat)
56.78%
>>>myfloat = .56785
>>>print "{:.2%}".format(myfloat)
56.78%
>>>myfloat = .56786
>>>print "{:.2%}".format(myfloat)
56.79%
(note the .5 case rounds down to 0 and .51 rounds up to 1)
Although, this has me thinking. I'm not certain if the .format method is
available in Python 2.5X branch (maybe it is in the future module, but I
don't have a working branch of 2.5 on this machine)
Either way, would you like me to proceed utilizing decimal, or go with the
string format.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:2>
Comment (by akaariai):
From [http://docs.python.org/library/stdtypes.html#str.format| Python's
documentation] it seems format is only available 2.6 onwards. I don't know
what is going to be the minimum required Python version for Django 1.5,
either 2.5 or 2.6. So, that could be a problem.
But looking more closely at this, it seems you should use the localization
framework of Django in some way or another. I guess the best way would be
to format according to what django.utils.formats.numberformat gives you.
Then you would not need to worry about decimal places, numberformat would
do that automatically for you. You should also check the use_l10n variable
from the context and pass it on to the numberformat. This should make the
tag more consistent with rest of Django, and also easier to write.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:3>
Comment (by eire1130):
Here's a patch using django.utils.formats.number_format. I'm not checking
for for USE_L10N or USE_THOUSAND_SEPARATOR explicitly, because
django.utils.formats.number_format and django.utils.numberformat already
check for it.
I still needed to use round(value) because numberformat doesn't give
predictable rounding (the unit-tests were failing).
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:4>
* stage: Accepted => Design decision needed
Comment:
I was thinking that context.use_l10n would be available, but I see it is
not available for filters. This is a bit sad, as now the percentage filter
doesn't respect {% localize on/off %} controls. I don't know what there is
to do about this. Not localizing the value seems inconsistent, and not
honoring the localize on/off controls seems even worse.
Any opinions? Maybe you should go with your first version. But then
.format isn't available before Python 2.6.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:5>
Comment (by akaariai):
Hmmh, I wonder if the best approach would be to just have a filter
|multiply "100".
Then you could do {{ val|multiply 100}}% and let number formatting deal
with all the ugly details of what to do for rounding etc.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:6>
Comment (by eire1130):
In thinking about this last night, I agree with your concerns, and I also
agree with your original point. I don't think using .format(%) is a good
way to go, even if it were well documented this is only a 2.6+ feature.
So, I think a couple of things:
1. It's fairly uncommon to have percents in the thousand+ range. Although
possible, of course. I work in financial services, and usually when
percentages get that big they lose their meaning, so instead I would say
something is 10X rather than 1,000%; nonetheless, people still do
represent very large numbers in percentage terms and so any system should
be able to accommodate using very large percentages; however, considering
the rarity and the special case, I would say someone can just write a
custom filter if the built-in doesn't meet their needs exactly. So, if
USE_L10N and USE_THOUSAND_SEPARATOR are both set to True in settings, and
for this discrete case the developer didn't want to use the
USE_THOUSAND_SEPARATOR they could simply write a custom filter, which is
where we are at today, except applying to everyone (and I think using
percentages is a fairly common use case)
2. However, I don't like things being sloppy (but then there are only so
many edge cases one can catch). The other alternative, and this is a bit
more forward looking, I've thought for a while it would be nice to have
filters as a class based system, where the filters themselves are methods
of a class which would be loaded such as {% load load_module|NameofClass
%}. Putting this together with the above concerns, instead loading filters
would like this: {% load load_module|NameofClass:Context %}, where the
class itself takes Context in it's init method.
This would give filters themselves direct access to context and all of the
other goodies therein (not just use_l10n). The syntax of course doesn't
have to be exactly like the above, but you can see my general idea.
That said, I know very little about that side of Django and how the
filters are initiated, so I have no idea what level of work this would
entail.
3. More on topic, since filters are limited to only one argument, the
precision argument could be dropped and always default to some arbitrary
length (I like this idea even less, as I need to adjust the precision
based on what I'm doing fairly often)
4. Or, of course, the number could be rounded before being passed to the
filter and simply not do any rounding at all.
5. I think {{ val|multiply 100}}% is a good enough workaround, but ideally
I would like percentage included (simply because I can see the typos that
would arise)
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:7>
Comment (by akaariai):
Any larger refactoring should be discussed on the django-developers
mailing list. There has been some talk about refactoring the template
system mainly for speed purposes. The idea is to restrict the access to
context to make the template system a lot (like 2-5x faster).
I think the ability to access use_l10n and use_tz variables of the context
in filters is needed. Maybe there is already some way, I am no expert of
the template system. Anyways, asking directions of what to do (especially
if you consider no.2 idea above) from the mailing list is the best
guidance I can give.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:8>
Comment (by fakotb):
This was left alone for a long time, but it may be a nice feature to have.
So I'm updating this ticket to let everybody know what the status is.
According to core developer jezdez, the context will not be available for
template filters for some time. However it's already possible to use
context in a template tag. So if we create a percentage template tag
instead of a filter it's possible to take into account localization.
Here is a page that specifies how a percentage should be written in
different languages:
http://www.unicode.org/cldr/charts/by_type/patterns.numbers.html#17acd127f9139476
The good news is that the % sign never changes. The placement of this sign
however differs per language, which makes things quite complicated. As
said before it is not good to use Pythons format. Not because Django still
wants to support 2.5 (it doesn't), but because the way format works
depends on the locale of the installation and not the locale set in
Django.
It would be nice to also support permille if we're putting effort in
supporting percentage.
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:9>
* status: new => closed
* resolution: => wontfix
Comment:
`|multiply` is a no go (look up "math filter" in this tracker if you want
to see an ugly troll).
It's unfortunate that the design of the Django template language prevents
us from writing a locale-aware filter :/ and a {% percent %} tag isn't a
nice API.
For lack of a better idea, I'm going to admit defeat and leave it up to
users to precompute percentages :(
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:10>
* needs_better_patch: 1 => 0
* has_patch: 1 => 0
* easy: 1 => 0
* stage: Design decision needed => Unreviewed
Comment:
I am taking the liberty to revisit this ticket and to reopen the
discussion.
I believe a lot has changed this implementing a percent filter was
initially dismissed. We are perfectly capable to render number via
`floatformat`. Shifting the point/comma by two places and adding a
`&percent;` does not seem unreachable.
IMHO we don't need to solve all possible cases here, but the most common
one. A value or rather ratio between 0 to 1 that is better contextualized
in percent. Thousand-separators seem unnecessary, since in most cases
values above 1 would usually not be displayed as percent unless you love
adding aditional zeros.
I would propose a filter as simple as `flaotformat` but with a percentage
sign and a fix decimal shift.
{{{
my_value = 1 / 42
my_value
>>> 0.023809523809523808
my_value|percent:2 # in a template
>>> "2.38 &percent;"
>>> "2,38 &percent;" # if you use comma
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:11>
* cc: Johannes Maron (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/17662#comment:12>