python - queries - ¿Utiliza.aggregate() en un valor introducido usando.extra(select={...}) en una consulta de Django?
group by django (2)
Aquí hay un ejemplo del problema y una solución de solución unideal. Toma este modelo de ejemplo:
class Rating(models.Model):
RATING_CHOICES = (
(1, ''1''),
(2, ''2''),
(3, ''3''),
(4, ''4''),
(5, ''5''),
)
rating = models.PositiveIntegerField(choices=RATING_CHOICES)
rater = models.ForeignKey(''User'', related_name=''ratings_given'')
ratee = models.ForeignKey(''User'', related_name=''ratings_received'')
Esta consulta agregada de ejemplo falla de la misma manera que la suya porque intenta hacer referencia a un valor no de campo creado con .extra()
.
User.ratings_received.extra(
select={''percent_positive'': ''ratings > 3''}
).aggregate(count=Avg(''positive''))
Una solución alternativa
El valor deseado se puede encontrar directamente utilizando la función de base de datos agregada (Promedio en este caso) dentro de la definición del valor extra:
User.ratings.extra(
select={''percent_positive'': ''AVG(rating >= 3)''}
)
Esta consulta generará la siguiente consulta SQL:
SELECT (AVG(rating >= 3)) AS `percent_positive`,
`ratings_rating`.`id`,
`ratings_rating`.`rating`,
`ratings_rating`.`rater_id`,
`ratings_rating`.`ratee_id`
FROM `ratings_rating`
WHERE `ratings_rating`.`ratee_id` = 1
A pesar de las columnas innecesarias en esta consulta, aún podemos obtener el valor deseado al aislar el valor percent_positive
:
User.ratings.extra(
select={''percent_positive'': ''AVG(rating >= 3)''}
).values(''percent_positive'')[0][''percent_positive'']
Estoy tratando de contar el número de veces que un jugador jugó cada semana de esta manera:
player.game_objects.extra(
select={''week'': ''WEEK(`games_game`.`date`)''}
).aggregate(count=Count(''week''))
Pero Django se queja de que
FieldError: Cannot resolve keyword ''week'' into field. Choices are: <lists model fields>
Puedo hacerlo en SQL sin formato como este
SELECT WEEK(date) as week, COUNT(WEEK(date)) as count FROM games_game
WHERE player_id = 3
GROUP BY week
¿Hay una buena forma de hacerlo sin ejecutar SQL sin formato en Django?
Puede usar una función agregada personalizada para generar su consulta:
WEEK_FUNC = ''STRFTIME("%%%%W", %s)'' # use ''WEEK(%s)'' for mysql
class WeekCountAggregate(models.sql.aggregates.Aggregate):
is_ordinal = True
sql_function = ''WEEK'' # unused
sql_template = "COUNT(%s)" % (WEEK_FUNC.replace(''%%'', ''%%%%'') % ''%(field)s'')
class WeekCount(models.aggregates.Aggregate):
name = ''Week''
def add_to_query(self, query, alias, col, source, is_summary):
query.aggregates[alias] = WeekCountAggregate(col, source=source,
is_summary=is_summary, **self.extra)
>>> game_objects.extra(select={''week'': WEEK_FUNC % ''"games_game"."date"''}).values(''week'').annotate(count=WeekCount(''pk''))
Pero como esta API no está documentada y ya requiere bits de SQL sin procesar, es mejor que utilices una consulta sin formato .