#python #django
#python #django
Вопрос:
У меня есть проект, который мне нужно открывать и закрывать заявки. Итак, это моя модель билета:
class Ticket(models.Model):
issue = models.CharField(max_length=100)
user = models.ForeignKey('Users', blank=True, null=True, related_name="tickets")
date_opened = models.DateTimeField('Date opened')
date_closed = models.DateTimeField('Date closed', blank=True, null=True)
def __str__(self):
return self.issue
def time_to_solve(self):
time_to_solve = self.date_opened - self.date_closed
out = [ time_to_solve.hours//60 ]
return '{:d} hours'.format(*out)
и я хочу вычислить среднее значение разницы во времени между date_opened
и date_closed
.
В моем views.py Я создал представление :
class Dashboard(ListView):
model = Ticket
template_name = 'assets/dashboard.html'
def get_context_data(self, **kwargs):
context = super(Dashboard, self).get_context_data(**kwargs)
context['time_to_complete'] = Q(status__contains='closed')).aggregate(time_opened = Avg('time_to_solve'))
return context
К сожалению, это не работает, потому что «time_to_solve» не является частью базы данных.
Как я могу этого добиться?
Ответ №1:
Вы можете агрегировать только поля модели, но это не сложно сделать в python:
tickets = Ticket.objects.filter(status__contains='closed')
average = sum(map(lambda x: x.time_to_solve(), tickets)) / tickets.count()
В этом случае time_to_solve
должно вернуться что-то вроде количества секунд, и вы можете отформатировать это так, как вам нужно сразу после этого.
В зависимости от количества заявок это может быть не самым быстрым решением. Если производительность является проблемой, вы можете захотеть использовать какую-то денормализацию.
Комментарии:
1. Я думал, что смогу использовать django без большого количества python, но теперь я вижу, что это неизбежно. Дело не в том, что мне не нравится программирование на Python (которым я много занимаюсь на самом деле), но я пытаюсь сократить кривую обучения. Если это правильный способ сделать это, я собираюсь попробовать его прямо сейчас.
2. Я получаю «неподдерживаемые типы операндов для : ‘int’ и ‘str'». Есть идеи?
3. @RobDel Это потому, что
time_to_solve
возвращает строку. Вы должны написать это как простоеreturn self.date_closed - self.date_opened
, таким образом, вы получите timedelta, которое вы можете использовать для вычисления среднего (вы можете добавлять и делить временные интервалы). Затем вам просто нужно отформатировать полученное среднее значение в виде строки.4. Как я уже сказал, time_to_solve должен возвращать число (я бы использовал секунды), и вы можете отформатировать его позже.
Ответ №2:
Я не думаю, что вы можете сделать это напрямую с помощью ORM. Вы можете сделать это на Python, но это приведет к извлечению всех закрытых строк тикетов из базы данных. Если вы хотите сделать это в SQL, вам нужно будет выразить свой запрос как необработанный SQL. Если вы используете PostgreSQL, вам может оказаться полезным следующее: работа с датами и временем в PostgreSQL.
Комментарии:
1. На самом деле это MySQL, но должен быть способ сделать это .. это очень просто.
Ответ №3:
Нашел ответ от друга в #irc — django на Freenode:
average = Ticket.objects.extra(
select={ 'date_difference': 'AVG(time_to_sec(TIMEDIFF(date_closed,date_opened)))'}).first().date_difference
context['average'] = "{:.2f}".format(average/86400)
return context
Таким образом, она возвращает среднее значение с точностью до 2 десятичных знаков и выполняет все на уровне базы данных, поэтому ее намного легче запускать, чем выборку всех строк.