>>>>>> quseryset = Model.objects.all()
>>>>>> queryset.aggregate( ( 'name', 'city' ), sum=( 'pay',
>>> 'some_other_field' ), avg=( 'pay', 'age' ), count=True )
>> I like this calling interface as an alternate method for its
>> fine-tuned control, but there are times it would be nice to not
>> have to have such tight coupling between the model and the
>> aggregation.  Otherwise, a change in the model requires not only
>> a change in the template to make use of the results, but in the
>> view (to request various aggregate functions) to add the desired
>> aggregation functions.
> 
> yes, and that is how it should be in my opinion. Why have the database
> calculate stuff you don't want?

My line of reasoning for allowing it to default to everything
would be the same reason that you can simply call .all() and get
all the fields rather than calling something crazy like

.all(model.field1, model.field3, model.field7)

to just selectively bring back the three fields that you "know"
you want.  It gives the template designer access to any of the
fields without needing to resort to involving the coder to make
changes to the view.  Any good database will not require a
table/hash-scan for each aggregate, but will gather the aggregate
stats in a single pass, so the cost of doing N fields vs doing
N+1 fields is barely noticeable.  And since N is bounded by the
number of fields in the model, this isn't apt to grow out of control.

>> As long as the resulting data can be easily accessed directly by
>> a template, any number of resulting formats would work just fine.
> 
> good point, the dictionary one wouldn't work very well in templates

Unless you have some brainstorm for making dictionaries work
nicely in templates, which is another bugaboo I see come up on
the ML occasionally :)

>> and then within the template refer to
>>
>>         <table>
>>         {% for item in items %}
>>                 <tr><td>{{ item.pay }}</td></tr>
>>         {% endfor %}
>>                 <tr><td>{{ items.aggregate.sum.pay }}</td></tr>
>>         </table>
> 
> this just seems wrong - doing something like this in a template just
> doesn't feel right, you should calculate the aggregation in the view -
> its an expensive operation you should always think through

The results should be cached so that if an aggregate is needed by
the template-designer (as per above), the cost happens once with
one additional DB hit.  I would be horrified if

        <tr>
        <td>{{ items.aggregate.sum.pay }}</td>
        <td>{{ items.aggregate.sum.hours }}</td>
        </tr>

triggered two database hits. :)  But if the aggregate stats are
needed, they should be generated on demand, just like .all()
where no DB call actually occurs until its data is used in things
like a {% for x in data %} call.  And if it's called, the DB is
only accessed once to bring back the data (okay, glossing over
fetchmany() calls here)


>> items = Model.objects.all()
>> return render_to_response('test.html', {
>>         'items': items,
>>         'stats': items.aggregate(),
>>         })
> 
> I think this should be:
> 
> items = Model.objects.all()
> return render_to_response('test.html', {
>         'stats_by_owner': items.aggregate( ('owner',), count=True,
> sum=('visits',) max=('rating', ), min=('rating', 'visits') ),
>         })

As mentioned, I like both syntaxes. :)  They seem to return
somewhat different things though.  The .aggregate() call would
only ever return one row for the entire dataset.  The
parameterized version would return multiple rows based on the
presence of a column-name tuple as the first parameter.
Otherwise, code starts getting unwieldy when you actually do want
all your fields.  I have a model with 20+ fields in it for
various types of money (FloatField) and time-durations
(PositiveIntegerField) involved in transactions (you've gotta
love billing information for cell-phone usage).  Without the
ability to say "sum and average everything you can", the code
would start looking like

items.aggregate((,), sum=(
        'field1',
        'field2',
...
        'field20',
        'field21',
        ), average=(
        'field1',
        'field2',
...
        'field20',
        'field21',
        ))

which makes for one very ugly view.  Even with a folding editor
like Vim, it's still there.

> {% for stat in stats_by_owner %}
>   Owner {{ stat.owner }} has written {{ stat.count }} articles wit
> ratings between {{ stat.min.rating }} and {{ stat.max.rating }}. His
> work was read {{ stat.sum.visits }} times in total and his least
> popular article was read {{ stat.min.visits }} times.
> {% endfor %}
> 
> the problem here is that if this should make any sense, owner should
> be an object, not just a field value (user id in this case), I believe
> though that this can be done...

I agree...when you have the leading tuple, this is a lovely
syntax.  It does have some rough edges where one's model
foolishly has fields such as "min" or "max" and suddenly you've
got a clash of ontologies.


> the first argument should also be optional - in case you want the total

Makes sense.

>> I think it will be a valuable addition as evaluation can be made
>> lazy (thus, it has no great impact on existing code), and I've
>> seen it requested several times in the Django-Users ML archives
>> where the answer was "Django doesn't do that, but you can drop to
>> hand-rolled SQL to do it for you."  I think it would help the
>> folks that don't think in SQL.
> 
> or the guys that don't want to rely on one DB engine

Do any of the supported DB engines not support groupings?  I
thought at least that much was pretty standard.  But yes,
requiring a developer to learn a second language (even if it's as
useful as knowing SQL is...) goes against the grain of Django's
"get out of the developer's way and let them just be productive
in Python yet do crazy-powerful stuff" philosophy.

Thanks again for your feedback and ideas.

-tkc




--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to