Skip to content

Commit

Permalink
Merge pull request #1550 from laws-africa/query-fix
Browse files Browse the repository at this point in the history
fix latest expression in taxonomy view; faster faceting.
  • Loading branch information
longhotsummer authored Sep 26, 2023
2 parents 578efe7 + 1e1a16b commit 950cde5
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 55 deletions.
12 changes: 9 additions & 3 deletions peachjam/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,13 @@ def filter_queryset(self, queryset, exclude=None):
attorneys = self.params.getlist("attorneys")
order_outcomes = self.params.getlist("order_outcomes")

# Order by date descending initially
queryset = queryset.order_by("-date", "title")
queryset = self.order_queryset(queryset, exclude)

if years and exclude != "years":
queryset = queryset.filter(date__year__in=years)

if alphabet and exclude != "alphabet":
queryset = queryset.order_by("title").filter(title__istartswith=alphabet)
queryset = queryset.filter(title__istartswith=alphabet)

if authors and exclude != "authors":
queryset = queryset.filter(authors__name__in=authors)
Expand Down Expand Up @@ -153,6 +152,13 @@ def filter_queryset(self, queryset, exclude=None):

return queryset

def order_queryset(self, queryset, exclude=None):
if self.cleaned_data.get("alphabet") and exclude != "alphabet":
queryset = queryset.order_by("title")
else:
queryset = queryset.order_by("-date", "title")
return queryset


class AttachmentFormMixin:
"""Admin form for editing models that extend from AbstractAttachmentModel."""
Expand Down
2 changes: 1 addition & 1 deletion peachjam/js/components/FilterFacets/SingleFacet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
/>
</div>
</div>
<div class="facets-scrollable">
<div :class="`${facet.type === 'letter-radio' ? '' : 'facets-scrollable'}`">
<template v-if="facet.type === 'checkboxes'">
<div
v-for="(option, optIndex) in facet.options"
Expand Down
4 changes: 2 additions & 2 deletions peachjam/models/core_document_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ def get_queryset(self):

class CoreDocumentQuerySet(PolymorphicQuerySet):
def latest_expression(self):
"""Select only the most recent expression for documents with the same frbr_uri."""
return self.distinct("work_frbr_uri").order_by("work_frbr_uri", "-date")
"""Select only the most recent expression for documents from the same work."""
return self.distinct("work_id").order_by("work_id", "-date")

def preferred_language(self, language):
"""Return documents whose language match the preferred one,
Expand Down
9 changes: 4 additions & 5 deletions peachjam/views/authors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ def get_queryset(self):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
doc_types = list(
set(
self.form.filter_queryset(
self.get_base_queryset(), exclude="doc_type"
).values_list("doc_type", flat=True)
)
self.form.filter_queryset(self.get_base_queryset(), exclude="doc_type")
.order_by()
.values_list("doc_type", flat=True)
.distinct()
)

context["author"] = self.author
Expand Down
45 changes: 24 additions & 21 deletions peachjam/views/courts.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,33 +70,36 @@ def get_context_data(self, **kwargs):

def populate_facets(self, context):
judges = list(
{
judge
for judge in self.form.filter_queryset(
self.get_base_queryset(), exclude="judges"
).values_list("judges__name", flat=True)
if judge
}
judge
for judge in self.form.filter_queryset(
self.get_base_queryset(), exclude="judges"
)
.order_by()
.values_list("judges__name", flat=True)
.distinct()
if judge
)

attorneys = list(
{
attorney
for attorney in self.form.filter_queryset(
self.get_base_queryset(), exclude="attorneys"
).values_list("attorneys__name", flat=True)
if attorney
}
attorney
for attorney in self.form.filter_queryset(
self.get_base_queryset(), exclude="attorneys"
)
.order_by()
.values_list("attorneys__name", flat=True)
.distinct()
if attorney
)

order_outcomes = list(
{
order_outcome
for order_outcome in self.form.filter_queryset(
self.get_base_queryset(), exclude="order_outcomes"
).values_list("order_outcome__name", flat=True)
if order_outcome
}
order_outcome
for order_outcome in self.form.filter_queryset(
self.get_base_queryset(), exclude="order_outcomes"
)
.order_by()
.values_list("order_outcome__name", flat=True)
.distinct()
if order_outcome
)

context["facet_data"] = {
Expand Down
66 changes: 43 additions & 23 deletions peachjam/views/generic_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,44 @@ class DocumentListView(ListView):
queryset = CoreDocument.objects.prefetch_related("nature", "work")

def get_base_queryset(self):
qs = self.queryset if self.queryset is not None else self.model.objects
return qs.preferred_language(get_language(self.request))
return self.queryset if self.queryset is not None else self.model.objects

def get_queryset(self):
return self.get_base_queryset()
qs = self.get_base_queryset()
return qs.preferred_language(get_language(self.request))


class FilteredDocumentListView(DocumentListView):
"""Generic list view for filtered document lists."""

form_class = BaseDocumentFilterForm
# Should the listing filter to include only the latest expressions of a document?
# This is a bit more expensive and so is opt-in. It is only necessary for document types
# that have multiple points-in-time (dated expressions), such as Legislation.
latest_expression_only = False

def get(self, request, *args, **kwargs):
self.form = self.form_class(request.GET)
self.form.is_valid()
return super().get(request, *args, **kwargs)

def get_queryset(self):
return self.filter_queryset(super().get_queryset())
qs = super().get_queryset()
filtered_qs = self.filter_queryset(qs)

if self.latest_expression_only:
# Getting only the latest expression requires ordering on the work, which breaks the actual ordering
# we want on the results. So, we take the filtered queryset and move that into a subquery,
# and then apply the normal ordering on a fresh copy of the main queryset.

# first, do the latest expression filtering
filtered_qs = filtered_qs.order_by().latest_expression()
# now move that into a subquery on the unfiltered queryset -- the filtering will come from the subquery
filtered_qs = qs.filter(pk__in=filtered_qs.values("id"))
# now apply the standard ordering
filtered_qs = self.form.order_queryset(filtered_qs)

return filtered_qs

def filter_queryset(self, qs):
return self.form.filter_queryset(qs)
Expand All @@ -67,31 +86,32 @@ def add_facets(self, context):
authors = []
# Initialize facet data values
natures = list(
{
doc_n
for doc_n in self.form.filter_queryset(
self.get_base_queryset(), exclude="natures"
).values_list("nature__name", flat=True)
if doc_n
}
doc_n
for doc_n in self.form.filter_queryset(
self.get_base_queryset(), exclude="natures"
)
.order_by()
.values_list("nature__name", flat=True)
.distinct()
if doc_n
)
if self.model in [GenericDocument, LegalInstrument]:
authors = list(
{
a
for a in self.form.filter_queryset(
self.get_base_queryset(), exclude="authors"
).values_list("authors__name", flat=True)
if a
}
a
for a in self.form.filter_queryset(
self.get_base_queryset(), exclude="authors"
)
.order_by()
.values_list("authors__name", flat=True)
.distinct()
if a
)

years = list(
set(
self.form.filter_queryset(
self.get_base_queryset(), exclude="years"
).values_list("date__year", flat=True)
)
self.form.filter_queryset(self.get_base_queryset(), exclude="years")
.order_by()
.values_list("date__year", flat=True)
.distinct()
)

context["doc_table_show_author"] = bool(authors)
Expand Down
2 changes: 2 additions & 0 deletions peachjam/views/taxonomy.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def get_context_data(self, **kwargs):
class TaxonomyDetailView(FilteredDocumentListView):
template_name = "peachjam/taxonomy_detail.html"
navbar_link = "taxonomy"
# taxonomies may include legislation, so we want to show the latest expression only
latest_expression_only = True

def get(self, request, *args, **kwargs):
self.taxonomy = self.get_taxonomy()
Expand Down

0 comments on commit 950cde5

Please sign in to comment.