1

I am trying to pass timezone.now() + timedelta(days=-2) and timezone.now() as arguments in django model method but am getting

def performance(user, timezone.now() + timedelta(days=-2), timezone.now()):
                                  ^
SyntaxError: invalid syntax

I know the error is as a result of the concatenation but I dont know how to solve this problem.

class User(AbstractUser):
    .........................
    fields
    .........................

    def get_performance(self, timezone.now() + timedelta(days=-2), timezone.now()):

        actual = Sum("scores", filter=Q(status="completed"))

        q = self.taskassignt.filter(
            due__gte=timezone.now() + timedelta(days=-2),
            due__lt=timezone.now() 
        ).annotate(actual=actual, total=Sum("scores"))

        return (q[0].actual / q[0].total) * 100
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555

1 Answers1

1

You need to specify a parameter name, so

def get_performance(self, start_time=timezone.now() + timedelta(days=-2), end_time=timezone.now()):
    actual = Sum("scores", filter=Q(status="completed"))
    q = self.taskassignt.filter(
        due__gte=start_time,
        due__lt=end_time 
    ).annotate(actual=actual, total=Sum("scores"))

    return 100 * q[0].actual / q[0].total

But this will not work, since the default value will be initialized once and then be used each time. That means that if your server is running for an entire year, start_time will still be the time from th previous year.

Usually one works with a None as default value, and if the parameter is indeed None, substitute it with a given expression, so:

def get_performance(self, start_time=None, end_time=None):
    if start_time is None:
        start_time = timezone.now() + timedelta(days=-2)
    if end_time is None:
        end_time = timezone.now()
    actual = Sum("scores", filter=Q(status="completed"))
    q = self.taskassignt.filter(
        due__gte=start_time,
        due__lt=end_time 
    ).annotate(actual=actual, total=Sum("scores"))

    return 100 * q[0].actual / q[0].total

It is however odd to have a 100 * q[0].actual / q[0].total. This means that you are only intersted in the first taskassignt, not in all. Likely you want to .aggregate(…) [Django-doc] instead of .annotate(…) [Django-doc]:

def get_performance(self, start_time=None, end_time=None):
    if start_time is None:
        start_time = timezone.now() + timedelta(days=-2)
    if end_time is None:
        end_time = timezone.now()
    actual = Sum("scores", filter=Q(status='completed'))
    q = self.taskassignt.filter(
        due__gte=start_time,
        due__lt=end_time 
    ).aggregate(actual=actual, total=Sum("scores"))

    return 100 * q['actual'] / q['total']
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • @ Willem Van Onsem Kindly look at this thread. My aim is to calculate emplayee either weekly, quarterly or yearly performance from task. each task carries scores. https://stackoverflow.com/questions/68644458/how-to-find-the-percentage-of-employee-scores-using-django/69038881?noredirect=1#comment122174650_69038881 – Thaddeaus Iorbee Sep 11 '21 at 17:12
  • ```IndexError: list index out of range``` this is the error that shows up when I call ```user.performance(timezone.now() + timedelta(days=-2), timezone.now())``` in views.py – Thaddeaus Iorbee Sep 11 '21 at 23:24