Trac user jbg has found a regression with the aggregation/annotation refactor #14030. The crux of the problem comes down to whether annotations and aggregations should respect constraints on model fields. The specific example raised is as follows:
Model.objects.aggregate(
sum_price=Sum('price', output_field=DecimalField(max_digits=5, decimal_places=2)))
Assuming the field "price" is defined as "DecimalField(max_digits=5, decimal_places=2)", it doesn't matter if output_field is defined or not, as the implicit F('price') will result in exactly the same behaviour.
Each row in the table will adhere to the max_digits and decimal_places restriction. It has to, it's part of the column definition. But once you sum those values together, they are going to overflow. The same problem would exist if you were to concatenate two CharFields with a max_length=10.
These constraints do not necessarily make sense because we're not persisting these values anywhere. They are read-only computations, and should not require bounds. If these values were to be persisted in another model, then the input fields on that model are required to ensure the values are valid.
I've implemented
https://github.com/django/django/pull/3655/ which effectively ignores the max_digits and decimal_places arguments in the base expression class. Subclasses are free to enforce validation if it is necessary. Further, callers using aren't required to supply bounds checking in this situation. This is valid (with my patch):
Model.objects.aggregate(
sum_price=Sum('price', output_field=DecimalField()))
And the same goes with CharField() not requiring a max_length argument.
Can anyone see any issues with this approach?
If the above seems sensible, I'll alter the test cases to remove arguments like decimal_places and max_length, and update the documentation to call out that these kinds of arguments are not used for annotations.
Thanks,
Josh