Index: django/db/models/sql/query.py =================================================================== --- django/db/models/sql/query.py (revision 8818) +++ django/db/models/sql/query.py (working copy) @@ -84,6 +84,7 @@ self.extra_tables = () self.extra_where = () self.extra_params = () + self.extra_having = () self.extra_order_by = () def __str__(self): @@ -186,6 +187,7 @@ obj.extra_tables = self.extra_tables obj.extra_where = self.extra_where obj.extra_params = self.extra_params + obj.extra_having = self.extra_having obj.extra_order_by = self.extra_order_by if self.filter_is_sticky and self.used_aliases: obj.used_aliases = self.used_aliases.copy() @@ -292,6 +294,9 @@ grouping = self.get_grouping() result.append('GROUP BY %s' % ', '.join(grouping)) + if self.extra_having: + result.append('HAVING %s' % self.extra_having[0]) + if ordering: result.append('ORDER BY %s' % ', '.join(ordering)) @@ -388,10 +393,14 @@ if self.extra_where and rhs.extra_where: raise ValueError("When merging querysets using 'or', you " "cannot have extra(where=...) on both sides.") + if self.extra_having and rhs.extra_having: + raise ValueError("When merging querysets using 'or', you " + "cannot have extra(having=...) on both sides.") self.extra_select.update(rhs.extra_select) self.extra_tables += rhs.extra_tables self.extra_where += rhs.extra_where self.extra_params += rhs.extra_params + self.extra_having += rhs.extra_having # Ordering uses the 'rhs' ordering, unless it has none, in which case # the current ordering is used. @@ -1567,7 +1576,7 @@ self.related_select_cols = [] self.related_select_fields = [] - def add_extra(self, select, select_params, where, params, tables, order_by): + def add_extra(self, select, select_params, where, params, tables, order_by, having): """ Adds data to the various extra_* attributes for user-created additions to the query. @@ -1598,6 +1607,8 @@ self.extra_params += tuple(params) if tables: self.extra_tables += tuple(tables) + if having: + self.extra_having += tuple(having) if order_by: self.extra_order_by = order_by Index: django/db/models/query.py =================================================================== --- django/db/models/query.py (revision 8818) +++ django/db/models/query.py (working copy) @@ -567,14 +567,14 @@ return obj def extra(self, select=None, where=None, params=None, tables=None, - order_by=None, select_params=None): + order_by=None, select_params=None, having=None): """ Adds extra SQL fragments to the query. """ assert self.query.can_filter(), \ "Cannot change a query once a slice has been taken" clone = self._clone() - clone.query.add_extra(select, select_params, where, params, tables, order_by) + clone.query.add_extra(select, select_params, where, params, tables, order_by, having) return clone def reverse(self):