Django Sum Aggregation from Int to Float - django

So i save my fees in cents, but want to display them in Euro. The conversion problem is that it first divides the integer by 100 and then converts to a float. It should be the other way around. How can i do that?
The following code should illustrate my Problem:
>>> from django.db.models import F, FloatField, Sum
>>> from payment.models import Payment
>>>
>>> paymentlist = Payment.objects.all()
>>> result = paymentlist.annotate(
... fees_in_cents=Sum(F('fees'), output_field=FloatField())).annotate(
... fees_in_euro=Sum(F('fees')/100, output_field=FloatField()))
>>>
>>> print(result[0].fees_in_cents, result[0].fees_in_euro)
120.0 1.0
fees_in_euro should obviously be 1.20

Divide fees value by 100.0
Example:
result = paymentlist.annotate(
fees_in_cents=Sum(F('fees'), output_field=FloatField())).annotate(
fees_in_euro=Sum(F('fees') / 100.0, output_field=FloatField())
)

Related

How could I generate random coefficients for polynomials using Sum( f(x), (x,0,b) )?

from sympy import Sum, Eq
from sympy.abc import n,x
import random
def polynomial(x):
i = 0
def random_value(i):
return random.choice([i for i in range(-10,10) if i not in [0]])
eq = Sum(random_value(i)*x**n, (n,0,random_value(i)))
display(Eq(eq,eq.doit(), evaluate=False))
polynomial(x)
polynomial(x)
With this code, the coefficients are always the same.
Also, I am not sure if the algebra evaluations are correct for b < 0 .
One way is to use IndexedBase to generate symbolic-placeholder coefficients, and then substitute them with numerical coefficients.
from sympy import Sum, Eq, Matrix, IndexedBase
from sympy.abc import n, x
import random
def polynomial(x):
# n will go from zero to this positive value
to = random.randint(0, 10)
# generate random coefficients
# It is important for them to be a sympy Matrix or Tuple,
# otherwise the substitution (later step) won't work
coeff = Matrix([random.randint(-10, 10) for i in range(to + 1)])
c = IndexedBase("c")
eq = Sum(c[n]*x**n, (n, 0, to)).doit()
eq = eq.subs(c, coeff)
return eq
display(polynomial(x))
display(polynomial(x))
Another ways is to avoid using Sum, relying instead on list-comprehension syntax and builtin sum:
def polynomial(x):
to = random.randint(0, 10)
coeff = [random.randint(-10, 10) for i in range(to + 1)]
return sum([c * x**n for c, n in zip(coeff, range(to + 1))])
display(polynomial(x))
display(polynomial(x))
You can pass a list of coefficients (with highest order coefficient first and constant last) directly to Poly and then convert that to an expression:
>>> from sympy import Poly
>>> from sympy.abc import x
>>> Poly([1,2,3,4], x)
Poly(x**3 + 2*x**2 + 3*x + 4, x, domain='ZZ')
>>> _.as_expr()
x**3 + 2*x**2 + 3*x + 4
>>> from random import randint, choice
>>> Poly([choice((-1,1))*randint(1,10) for i in range(randint(0, 10))], x).as_expr()
-3*x**4 + 3*x**3 - x**2 - 6*x + 2

Division between two annotations

I'm creating those two annotations as it follows:
cs = Champion.objects.all()
total_games = Match.objects.all().count()
cs = cs.annotate(
picked_games=Count(
expression='participants__match__id',
filter=Q(participants__role='BOTTOM'),
distinct=True
),
total_games=Value(str(total_games), output_field=IntegerField())
)
And everthing's alright until here. I fetch both the picked_games and total_games with correct results.
>>> cs.get(name='Jhin').picked_games
27544
>>> cs.get(name='Jhin').total_games
97410
However, if i try to divide one by another:
cs = cs.annotate(
pick_rate=ExpressionWrapper(
expression=F('picked_games') / F('total_games'),
output_field=FloatField()
)
)
This results on a 0:
>>> cs.get(name='Jhin').pick_rate
0.0
I don't understand what's problem here..
I can get the result if divide them externally, so why can't i get the result on a different column for the whole queryset?
>>> cs.get(name='Jhin').picked_games / cs.get(name='Jhin').total_games
0.28319474386613286
You should cast the numerator (or denominator) to a float before making the division, otherwise the PostgreSQL database will use integer division and thus truncate towards zero. You thus can work with:
from django.db.models import Count, F, FloatField, Q
from django.db.models.functions import Cast
total_games = Match.objects.all().count()
Champion.objects.annotate(
picked_games=Count(
expression='participants__match__id',
filter=Q(participants__role='BOTTOM'),
distinct=True
)
).annotate(
pick_rate=Cast('picked_games', output_field=FloatField()) / total_games
)

Periodicity of SymPy trigonometric function

Sympy's trigonometric functions takes periodic argument into account.
from sympy import pi, sin, Symbol
n = Symbol('n', integer=True)
>>> sin(2*pi + 4)
sin(4)
>>> sin(n*pi)
0
However, it seems that it does not support this feature...
n = Symbol('n', integer=True)
>>> sin(2*n*pi + 4)
sin(2*n*pi + 4) # Expected sin(4)
.simplify() or .doit() was not working. Is there any function or method to convert sin(2*n*pi + 4) to sin(4)?
You could use trigsimp or seemingly clunky expansion and rewriting:
>>> eq = sin(2*n*pi + 4)
>>> eq.rewrite(exp).expand().rewrite(sin).expand()
sin(4)
>>> trigsimp(eq)
sin(4)

Converting the input of DecimalField of WTForm to a float?-Flask

The input I give to a DecimalField of WTFform in Flask application is being converted to a string. I need it be an int or float in order to perform any
mathematical operation?
Any help would be appreciated.
TIA
wtforms.DecimalField produces a decimal.Decimal instance.
>>> import wtforms
>>> from webob.multidict import MultiDict
>>> class F(wtforms.Form):
... foo = wtforms.DecimalField()
...
>>> f = F(formdata=MultiDict(foo=3.45))
>>> val = f.data['foo']
>>> val
Decimal('3.45000000000000017763568394002504646778106689453125')
>>> type(val)
<class 'decimal.Decimal'>
The object can be used in calculations:
>>> val * 4
Decimal('13.80000000000000071054273576')
>>> val + 2
Decimal('5.450000000000000177635683940')
or can be converted to a float or int using the respective builtin functions
>>> float(val)
3.45
>>> int(val)
3

Django: Identify the urls that provide duplicate content and set a canonical link

models.py
class People(models.Model):
name = models.CharField(max_length=16)
meters_away = models.IntegerField()
Lets populate the db:
>>> from people.models import People
>>> a = People()
>>> a.name = 'George'
>>> a.meters_away = 15
>>> a.save()
>>> b = People()
>>> b.name = 'Jim'
>>> b.meters_away = 10
>>> b.save()
Supposing that we have a url that returns all people in a range of x meters:
http://example.com/range/<meters>
This url scheme accepts 3 hits as follows:
http://example.com/range/20
http://example.com/range/30
http://example.com/range/40
Those hits will create the following queries:
>>> hit1 = People.objects.filter(meters_away__lt=20)
>>> hit2 = People.objects.filter(meters_away__lt=30)
>>> hit3 = People.objects.filter(meters_away__lt=40)
Where:
>>> list(hit1) == list(hit2) == list(hit3)
>>> True
This means that example.com, will serve 3 different urls with the same content.
From a SEO point of view, how could all the possible urls (meters: 21, 22, 23, 24, 30, 40 etc) be filtered in a way that a canonical url is appended to them?
The way i understood your question, you may want to get the maximum distance in meters that produce the same result as the current distance (say m meters):
next_number = People.objects.filter(meters_away__gte=m).order_by('meters_away')[:1]
next_number = next_number[0] if next_number else m
and the canonical url will be:
http://example.com/range/<next_number>