Ticket #1435: aggr_functions-r3897.diff
File aggr_functions-r3897.diff, 13.6 KB (added by , 18 years ago) |
---|
-
django/db/models/manager.py
51 51 def all(self): 52 52 return self.get_query_set() 53 53 54 def count(self): 55 return self.get_query_set().count() 54 def count(self,fieldname="*"): 55 """Returns the number of rows in the default case. Else returns the number of non-null entries in the column corresponding to the fieldname. 56 """ 57 return self.get_query_set().count(fieldname) 56 58 57 59 def dates(self, *args, **kwargs): 58 60 return self.get_query_set().dates(*args, **kwargs) … … 99 101 def values(self, *args, **kwargs): 100 102 return self.get_query_set().values(*args, **kwargs) 101 103 104 # Aggregate functions (column-oriented) 105 106 def get_aggregate(self,functype,column): 107 return self.get_query_set().get_aggregate(functype,column) 108 109 def get_aggregates(self,functypes,column): 110 return self.get_query_set().get_aggregates(functypes,column) 111 112 def sum(self,fieldname): 113 return self.get_query_set().sum(fieldname) 114 115 def min(self,fieldname): 116 return self.get_query_set().min(fieldname) 117 118 def max(self,fieldname): 119 return self.get_query_set().max(fieldname) 120 121 def avg(self,fieldname): 122 return self.get_query_set().avg(fieldname) 123 124 def stddev(self,fieldname): 125 return self.get_query_set().stddev(fieldname) 126 127 def median(self,fieldname): 128 return self.get_query_set().median(fieldname) 129 102 130 class ManagerDescriptor(object): 103 131 # This class ensures managers aren't accessible via model instances. 104 132 # For example, Poll.objects works, but poll_obj.objects raises AttributeError. -
django/db/models/query.py
1 1 from django.db import backend, connection, transaction 2 2 from django.db.models.fields import DateField, FieldDoesNotExist 3 from django.db.models.fields import DateField, IntegerField, FloatField, FieldDoesNotExist 3 4 from django.db.models import signals 4 5 from django.dispatch import dispatcher 5 6 from django.utils.datastructures import SortedDict … … 157 158 combined._filters = self._filters | other._filters 158 159 return combined 159 160 161 ############################################## 162 # HELPER METHODS THAT EXAMINE FIELD METADATA # 163 ############################################## 164 165 def is_number(self, fieldname): 166 "Returns flag, True for integer. False for float. Non-float and non-integer raises either a FieldDoesNotExist or TypeError exception." 167 field = self.model._meta.get_field(fieldname) 168 # Let the FieldDoesNotExist exception propogate 169 if isinstance(field, IntegerField): 170 return True 171 if isinstance(field, FloatField): 172 return False 173 raise TypeError, "Field %s for Model %s is not an IntegerField or FloatField" % (fieldname, self.model._meta.object_name) 174 175 def is_number_or_date(self, fieldname): 176 "Returns 0 for int; 1 for float; 2 for date. Raises either a FieldDoesNotExist or TypeError exception if not an Integer, Float or Date." 177 field = self.model._meta.get_field(fieldname) 178 # Let the FieldDoesNotExist exception propogate 179 if isinstance(field, IntegerField): 180 return 0 181 if isinstance(field, FloatField): 182 return 1 183 if isinstance(field, DateField): 184 return 2 185 raise TypeError, "Field %s for Model %s is not an IntegerField, FloatField or DateField" % (fieldname, self.model._meta.object_name) 186 160 187 #################################### 161 188 # METHODS THAT DO DATABASE QUERIES # 162 189 #################################### … … 185 212 setattr(obj, k[0], row[index_end+i]) 186 213 yield obj 187 214 188 def count(self ):189 "Performs a SELECT COUNT( ) and returns the number of records as an integer."215 def count(self,fieldname="*"): 216 "Performs a SELECT COUNT(coulmn) and returns the number of records as an integer." 190 217 counter = self._clone() 191 218 counter._order_by = () 192 219 counter._offset = None … … 194 221 counter._select_related = False 195 222 select, sql, params = counter._get_sql_clause() 196 223 cursor = connection.cursor() 224 if fieldname == '*': 225 column = '*' 226 else: 227 column = "%s.%s" % (backend.quote_name(self.model._meta.db_table), 228 backend.quote_name(fieldname)) 197 229 if self._distinct: 198 id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), 199 backend.quote_name(self.model._meta.pk.column)) 200 cursor.execute("SELECT COUNT(DISTINCT(%s))" % id_col + sql, params) 230 if fieldname == '*': 231 column = "%s.%s" % (backend.quote_name(self.model._meta.db_table), 232 backend.quote_name(self.model._meta.pk.column)) 233 cursor.execute("SELECT COUNT(DISTINCT(%s))" % column + sql, params) 201 234 else: 202 cursor.execute("SELECT COUNT( *)"+ sql, params)235 cursor.execute("SELECT COUNT(%s)" % (column) + sql, params) 203 236 return cursor.fetchone()[0] 204 237 238 def get_aggregate(self,type,column): 239 "Performs the specified aggregate function on the named column." 240 agg = self._clone() 241 agg._order_by = () 242 agg._offset = None 243 agg._limit = None 244 agg._select_related = False 245 select, sql, params = agg._get_sql_clause() 246 cursor = connection.cursor() 247 sel = "SELECT %s(%s)" % (type, column) 248 cursor.execute(sel + sql, params) 249 return cursor.fetchone()[0] 250 251 def get_aggregates(self,types,column): 252 "Performs the specified aggregate functions on the named column." 253 agg = self._clone() 254 agg._order_by = () 255 agg._offset = None 256 agg._limit = None 257 agg._select_related = False 258 select, sql, params = agg._get_sql_clause() 259 cursor = connection.cursor() 260 sel = [] 261 sel.append( "SELECT" ) 262 for type in types: 263 sel.append ( "%s(%s)," % (type, column)) 264 select = " ".join(sel)[:-1] 265 cursor.execute(select + sql, params) 266 return cursor.fetchone() 267 268 def sum(self, fieldname): 269 "Performs a SELECT SUM() on the specified column." 270 isInt = self.is_number(fieldname) 271 column = self.model._meta.get_field(fieldname).column 272 result = self.get_aggregate("SUM",column) 273 if isInt: 274 return int(result) 275 return result 276 277 def avg(self, fieldname): 278 "Performs a SELECT AVG() on the specified column." 279 self.is_number(fieldname) 280 column = self.model._meta.get_field(fieldname).column 281 return self.get_aggregate("AVG",column) 282 283 def stddev(self, fieldname): 284 "Performs a SELECT STDDEV() on the specified column." 285 self.is_number(fieldname) 286 column = self.model._meta.get_field(fieldname).column 287 return self.get_aggregate("STDDEV",column) 288 289 def min(self, fieldname): 290 "Performs a SELECT MIN() on the specified column." 291 self.is_number_or_date(fieldname) 292 column = self.model._meta.get_field(fieldname).column 293 return self.get_aggregate("MIN",column) 294 295 def max(self, fieldname): 296 "Performs a SELECT MAX() on the specified column." 297 self.is_number_or_date(fieldname) 298 column = self.model._meta.get_field(fieldname).column 299 return self.get_aggregate("MAX",column) 300 301 def median(self, fieldname): 302 "Returns the median value for the specified column." 303 coltype = self.is_number_or_date(fieldname) 304 column = self.model._meta.get_field(fieldname).column 305 fetcher = self._clone() 306 fetcher._order_by = (column,) 307 fetcher._offset = None 308 fetcher._limit = None 309 fetcher._select_related = False 310 select, sql, params = fetcher._get_sql_clause() 311 sel = "SELECT %s" % (column) 312 cursor = connection.cursor() 313 cursor.execute(sel + sql, params) 314 rows = cursor.fetchall() 315 midvalue = len(rows) / 2 316 if coltype == 2: 317 # returning a date 318 return str(rows[midvalue][0]) 319 else: 320 return rows[midvalue][0] 321 205 322 def get(self, *args, **kwargs): 206 323 "Performs the SELECT and returns a single object matching the given keyword arguments." 207 324 clone = self.filter(*args, **kwargs) -
docs/db-api.txt
844 844 845 845 Note ``latest()`` exists purely for convenience and readability. 846 846 847 Aggregate Functions 848 ------------------- 849 850 Aggregate functions perform calculations on columns. Typically 851 they return a single value. They are in two groups: high_level 852 and low_level. 853 854 High Level Functions 855 ~~~~~~~~~~~~~~~~~~~~ 856 857 The high_level functions are sum(), min(), max(), avg(), stddev() 858 and median(). Each takes a fieldname as an argument. The type of 859 the field is checked for correctness as only certain datatypes are 860 allowed for each of the high level functions. 861 862 sum(fieldname) 863 ~~~~~~~~~~~~~~ 864 865 Returns the sum of the named field. The field must be an 866 IntegerField or a FloatField. The returned value corresponds 867 with the type of the column. 868 869 min(fieldname), max(fieldname) 870 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 871 872 Returns the minimum or maximum value of the named field. The field 873 must be an IntegerField, FloatField or DateField. The returned value 874 corresponds with the type of the field. (This is a string 875 representation if the field is a DateField.) 876 877 avg(fieldname) 878 ~~~~~~~~~~~~~~ 879 880 Returns the average of the named field. The field must be an 881 IntegerField or a FloatField. The returned value is a Float. 882 883 stddev(fieldname) 884 ~~~~~~~~~~~~~~~~~ 885 886 Returns the standard deviation of the named field. The field must be an 887 IntegerField or a FloatField. The returned value is a Float. 888 (Not supported on sqlite3. You get an OperationError exception.) 889 890 median(fieldname) 891 ~~~~~~~~~~~~~~~~~ 892 893 Returns the median value of the named field. The field 894 must be an IntegerField, FloatField or DateField. The returned 895 value corresponds with the type of the field. (This is a string 896 representation if the column is a DateField.) Unlike the other 897 functions in this group, this function does not use the DB 898 supplied capabilities. It fetches all of the values of the field 899 ordered by that field and returns the middle value. (If there 900 are an even number of values, the second of the two middle 901 values is returned.) 902 903 Low Level Functions 904 ~~~~~~~~~~~~~~~~~~~ 905 906 There are two low level functions: get_aggregate() and 907 get_aggregates(). They do minimal checking and allow for 908 powerful queries that potentially return multiple values 909 and/or combine multiple column arithmetically. 910 911 The low_level functions take columnnames instead of fieldnames. 912 You must do your own conversion from fieldname to columnname 913 if you are taking advantage of the fieldname mapping. (By 914 default fieldnames and columnnames match each other and so 915 most users will not have to worry about this distinction.) 916 917 get_aggregate(type,columnname) 918 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 919 920 This function supplies direct support for all database-supplied 921 aggregate functions. The type parameter is the name of an aggregate 922 function such as 'SUM', 'VARIANCE' or so forth limited only by 923 what set of functions your particular database supports. The return 924 value uses whatever type your database connonically returns. (Most 925 databases return the same type as the named column, although this 926 is not the case for some functions such as "avg" or "stddev" which 927 always returns a Float. Also note that sqlite3 always returns a Float 928 for all aggregate function.) 929 930 Note that the columnname is not explicitly checked for type and 931 so it is possible to combine columns arithmetically (with care!) 932 as follows: 933 934 Inventory.objects.get_aggregate('AVG','quantity*price') 935 936 This returns the average value of the 'quantity' column multiplied 937 by the 'price' column. 938 939 Meals.objects.get_aggregate('MAX','price+tax+tip') 940 941 This returns the highest priced meal which is calculated by the 942 database by adding the 'price', the 'tax' and the 'tip' columns. 943 944 (As a repeat warning: Don't forget to get the columnname from your 945 fieldname if you are using fieldname mapping.) 946 947 get_aggregates(types,columnname) 948 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 949 950 This function allows a single SQL operation to perform multiple 951 aggregate functions. The types field is an iterable list of 952 aggregate function names. The columnname is handled in the same 953 manner as with the get_aggregate() function. For example: 954 955 Inventory.objects.get_aggregates(['AVG','MIN','MAX'],'quantity') 956 957 The results are returned in an array. 958 959 Usage 960 ~~~~~ 961 962 Typical use targets all of the rows in the targeted table. 963 For example: 964 965 Articles.objects.sum('wordcount') 966 967 However it is possible to combine the aggregate functions with 968 judicious filtering. For example: 969 970 Poll.objects.filter(question__contains='football').min('pub_date') 971 972 Exceptions 973 ~~~~~~~~~~ 974 975 The most common exceptions encountered when using aggregate functions are: 976 977 FieldDoesNotExist - the columnname is not found. 978 979 TypeError - the named column uses an unsupported type. 980 981 OperationError - the functype is not supported by the database. 982 983 847 984 Field lookups 848 985 ------------- 849 986