Add patterns for joining tables in API list methods

i.e. we needed to do an *outer* join on User.person since that can be null
This commit is contained in:
Lance Edgar 2018-11-27 02:21:38 -06:00
parent 93aa96a339
commit b7319fd152
3 changed files with 43 additions and 10 deletions

View file

@ -118,12 +118,39 @@ class APIMasterView(APIView):
""" """
return self.sortcol(order_by) return self.sortcol(order_by)
def sortcol(self, field_name, model_name=None): def sortcol(self, *args):
""" """
Return a simple ``SortColumn`` object which denotes the field and Return a simple ``SortColumn`` object which denotes the field and
optionally, the model, to be used when sorting. optionally, the model, to be used when sorting.
""" """
return SortColumn(field_name, model_name) if len(args) == 1:
return SortColumn(args[0])
elif len(args) == 2:
return SortColumn(args[1], args[0])
else:
raise ValueError("must pass 1 arg (field_name) or 2 args (model_name, field_name)")
def join_for_sort_spec(self, query, sort_spec):
"""
This should apply any joins needed on the given query, to accommodate
requested sorting as per ``sort_spec`` - which will be non-empty but
otherwise no claims are made regarding its contents.
Please override as necessary, but in all cases you should return a
query, either untouched or else with join(s) applied.
"""
model_name = sort_spec[0].get('model')
return self.join_for_sort_model(query, model_name)
def join_for_sort_model(self, query, model_name):
"""
This should apply any joins needed on the given query, to accommodate
requested sorting on a field associated with the given model.
Please override as necessary, but in all cases you should return a
query, either untouched or else with join(s) applied.
"""
return query
def make_pagination_spec(self): def make_pagination_spec(self):
@ -153,6 +180,7 @@ class APIMasterView(APIView):
# maybe sort query # maybe sort query
sort_spec = self.make_sort_spec() sort_spec = self.make_sort_spec()
if sort_spec: if sort_spec:
query = self.join_for_sort_spec(query, sort_spec)
query = apply_sort(query, sort_spec) query = apply_sort(query, sort_spec)
# maybe paginate query # maybe paginate query

View file

@ -43,16 +43,20 @@ class UserView(APIMasterView):
def normalize(self, user): def normalize(self, user):
return { return {
'username': user.username, 'username': user.username,
'person_name': six.text_type(user.person or ''), 'person_display_name': (user.person.display_name or '') if user.person else '',
'active': user.active, 'active': user.active,
} }
def interpret_sortcol(self, order_by): def interpret_sortcol(self, order_by):
if order_by == 'person_name': if order_by == 'person_display_name':
return self.sortcol('display_name', 'Person') return self.sortcol('Person', 'display_name')
return self.sortcol(order_by) return self.sortcol(order_by)
def join_for_sort_model(self, query, model_name):
if model_name == 'Person':
query = query.outerjoin(model.Person)
return query
@view(permission='users.list') @view(permission='users.list')
def collection_get(self): def collection_get(self):
return self._collection_get() return self._collection_get()

View file

@ -88,17 +88,18 @@ var app = new Vue({
data: { data: {
columns: [ columns: [
'username', 'username',
'person_name', 'person_display_name',
'active' 'active'
], ],
options: { options: {
filterable: false, filterable: false,
headings: {
person_display_name: "Person"
},
sortable: [ sortable: [
'username', 'username',
'person_name', 'person_display_name',
'active' 'active'
// TODO: add sort for Person.display_name
// 'person'
], ],
orderBy: { orderBy: {
column: 'username', column: 'username',