Skip to content

Commit

Permalink
feat(generic): fix and extend the columns selector
Browse files Browse the repository at this point in the history
The column selector now gets initialized with the correct initial values
and it can now also cope with additional choices, like annotations and
the default table fields.
The `get_table_kwargs` method was updated to be able to show all the
selected columns.

Co-authored-by: Matthias Schlögl <matthias.schloegl@oeaw.ac.at>

Closes: #735
  • Loading branch information
b1rger committed Jun 28, 2024
1 parent aa3b742 commit d87ccfa
Showing 1 changed file with 50 additions and 9 deletions.
59 changes: 50 additions & 9 deletions apis_core/generic/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,39 @@ def get_table_class(self):

def get_table_kwargs(self):
kwargs = super().get_table_kwargs()
columns = self.request.GET.getlist("columns", [])
column_fields = [
field for field in self.model._meta.fields if field.name in columns

# we look at the selected columns and exclude
# all modelfields that are not part of that list
selected_columns = (
self.request.GET.getlist("columns")
if self.request.GET
else self.get_filterset(self.get_filterset_class()).form["columns"].initial
)
modelfields = self.model._meta.fields
kwargs["exclude"] = [
field.name for field in modelfields if field.name not in selected_columns
]

# now we look at the selected columns and
# add all modelfields and annotated fields that
# are part of the selected columns to the extra_columns
annotationfields = list()
for key, value in self.object_list.query.annotations.items():
fake_field = getattr(value, "field", value.output_field)
setattr(fake_field, "name", key)
annotationfields.append(fake_field)
extra_fields = list(
filter(
lambda x: x.name in selected_columns,
modelfields + tuple(annotationfields),
)
)
kwargs["extra_columns"] = [
(field.name, library.column_for_field(field, accessor=field.name))
for field in column_fields
for field in extra_fields
if field.name not in self.get_table_class().base_columns
]

return kwargs

def get_filterset_class(self):
Expand All @@ -122,21 +147,37 @@ def get_filterset_class(self):
filterset_class = first_member_match(filterset_modules, GenericFilterSet)
return filterset_factory(self.model, filterset_class)

def _get_columns_choices(self, columns_exclude):
# we start with the model fields
choices = [
(field.name, field.verbose_name) for field in self.model._meta.fields
]
# we add any annotated fields to that
choices += [(key, key) for key in self.get_queryset().query.annotations.keys()]
# now we drop all the choices that are listed in columns_exclude
choices = list(filter(lambda x: x[0] not in columns_exclude, choices))
return choices

def _get_columns_initial(self, columns_exclude):
return [
field
for field in self.get_table().columns.names()
if field not in columns_exclude
]

def get_filterset(self, filterset_class):
"""
We override the `get_filterset` method, so we can inject a
`columns` selector into the form
"""
filterset = super().get_filterset(filterset_class)
columns_exclude = filterset.form.columns_exclude

# we inject a `columns` selector in the beginning of the form
columns = forms.MultipleChoiceField(
required=False,
choices=[
(field.name, field.verbose_name)
for field in self.model._meta.fields
if field.name not in filterset.form.columns_exclude
]
choices=self._get_columns_choices(columns_exclude),
initial=self._get_columns_initial(columns_exclude),
)
filterset.form.fields = {**{"columns": columns}, **filterset.form.fields}

Expand Down

0 comments on commit d87ccfa

Please sign in to comment.