Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update AssessmentValue global API #955

Merged
merged 14 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 92 additions & 25 deletions hawc/apps/assessment/exports.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,108 @@
import pandas as pd
from django.conf import settings
from ..common.exports import Exporter, ModelExport
from ..common.models import sql_display, str_m2m
from ..study.exports import StudyExport
from . import constants

from ..common.exports import ModelExport
from ..common.helper import FlatFileExporter
from ..common.models import sql_format
from .models import AssessmentValue

class AssessmentValueExport(ModelExport):
def get_value_map(self) -> dict:
return {
"evaluation_type": "evaluation_type_display",
"system": "system",
"value_type": "value_type_display",
"value": "value",
"value_unit": "value_unit",
"adaf": "adaf",
"confidence": "confidence",
"duration": "duration",
"basis": "basis",
"pod_type": "pod_type",
"pod_value": "pod_value",
"pod_unit": "pod_unit",
"uncertainty": "uncertainty_display",
"species_studied": "species_studied",
"evidence": "evidence",
"tumor_type": "tumor_type",
"extrapolation_method": "extrapolation_method",
"comments": "comments",
"extra": "extra",
"created": "created",
"last_updated": "last_updated",
}

class DSSToxExport(ModelExport):
def get_value_map(self):
def get_annotation_map(self, query_prefix: str) -> dict:
return {
"dtxsid": "dtxsid",
"dashboard_url": "dashboard_url",
"img_url": "img_url",
"content": "content",
"evaluation_type_display": sql_display(
query_prefix + "evaluation_type", constants.EvaluationType
),
"value_type_display": sql_display(query_prefix + "value_type", constants.ValueType),
"uncertainty_display": sql_display(
query_prefix + "uncertainty", constants.UncertaintyChoices
),
}

def prepare_df(self, df):
return self.format_time(df)


class AssessmentExport(ModelExport):
def get_value_map(self) -> dict:
return {
"id": "id",
"name": "name",
"cas": "cas",
"dtxsids": "dtxsids__name",
"year": "year",
"created": "created",
"last_updated": "last_updated",
}

def get_annotation_map(self, query_prefix):
img_url_str = (
f"https://api-ccte.epa.gov/chemical/file/image/search/by-dtxsid/{{}}?x-api-key={settings.CCTE_API_KEY}"
if settings.CCTE_API_KEY
else "https://comptox.epa.gov/dashboard-api/ccdapp1/chemical-files/image/by-dtxsid/{}"
)
return {
"dashboard_url": sql_format(
"https://comptox.epa.gov/dashboard/dsstoxdb/results?search={}",
query_prefix + "dtxsid",
),
"img_url": sql_format(img_url_str, query_prefix + "dtxsid"),
"dtxsids__name": str_m2m(query_prefix + "dtxsids__dtxsid"),
}

def prepare_df(self, df):
return self.format_time(df)


class ValuesListExport(FlatFileExporter):
def build_df(self) -> pd.DataFrame:
return AssessmentValue.objects.get_df()
class AssessmentDetailExport(ModelExport):
def get_value_map(self) -> dict:
return {
"project_type": "project_type",
"project_status": "project_status_display",
"project_url": "project_url",
"peer_review_status": "peer_review_status_display",
"qa_id": "qa_id",
"qa_url": "qa_url",
"report_id": "report_id",
"report_url": "report_url",
"extra": "extra",
"created": "created",
"last_updated": "last_updated",
}

def prepare_df(self, df):
return self.format_time(df)

def get_annotation_map(self, query_prefix: str) -> dict:
return {
"project_status_display": sql_display(
query_prefix + "project_status", constants.Status
),
"peer_review_status_display": sql_display(
query_prefix + "peer_review_status", constants.PeerReviewType
),
}


class AssessmentExporter(Exporter):
def build_modules(self) -> list[ModelExport]:
return [
AssessmentExport("assessment", "assessment"),
AssessmentDetailExport("assessment_detail", "assessment__details"),
dannypeterson marked this conversation as resolved.
Show resolved Hide resolved
AssessmentValueExport("assessment_value", ""),
StudyExport(
"study", "study", include=("id", "short_citation", "hero_id", "pubmed_id", "doi")
),
]
35 changes: 35 additions & 0 deletions hawc/apps/assessment/filterset.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
BaseFilterSet,
ExpandableFilterForm,
InlineFilterForm,
OrderingFilter,
PaginationFilter,
)
from ..common.helper import new_window_a
from ..myuser.models import HAWCUser
Expand Down Expand Up @@ -165,3 +167,36 @@ def create_form(self):

class EffectTagFilterSet(df.FilterSet):
name = df.CharFilter(lookup_expr="icontains")


class AssessmentValueFilterSet(df.FilterSet):
name = df.CharFilter(
field_name="assessment__name",
lookup_expr="icontains",
label="Assessment name",
)
cas = df.CharFilter(
field_name="assessment__cas",
label="Assessment CAS",
)
dtxsid = df.CharFilter(
field_name="assessment__dtxsids__dtxsid",
label="Assessment DTXSID",
)
project_type = df.CharFilter(
field_name="assessment__details__project_type",
lookup_expr="icontains",
label="Assessment project type",
)
year = df.CharFilter(field_name="assessment__year", label="Assessment year")

order_by = OrderingFilter(
fields=(("assessment__name", "name"), ("assessment__id", "assessment_id")),
initial="name",
)

paginate_by = PaginationFilter()

class Meta:
model = models.AssessmentValue
fields = ("value_type",)
50 changes: 1 addition & 49 deletions hawc/apps/assessment/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.db.models import Case, Exists, OuterRef, Q, QuerySet, Value, When
from reversion.models import Version

from ..common.helper import HAWCDjangoJSONEncoder, map_enum
from ..common.helper import HAWCDjangoJSONEncoder
from ..common.models import BaseManager, replace_null, str_m2m
from . import constants

Expand Down Expand Up @@ -202,54 +202,6 @@ class DatasetManager(BaseManager):
class AssessmentValueManager(BaseManager):
assessment_relation = "assessment"

def get_df(self) -> pd.DataFrame:
"""Get a dataframe of Assessment Values from given Queryset of Values."""
mapping: dict[str, str] = {
"assessment_id": "assessment_id",
"assessment__name": "assessment_name",
"assessment__created": "assessment_created",
"assessment__last_updated": "assessment_last_updated",
"assessment__details__project_type": "project_type",
"assessment__details__project_status": "project_status",
"assessment__details__project_url": "project_url",
"assessment__details__peer_review_status": "peer_review_status",
"assessment__details__qa_id": "qa_id",
"assessment__details__qa_url": "qa_url",
"assessment__details__report_id": "report_id",
"assessment__details__report_url": "report_url",
"assessment__details__extra": "assessment_extra",
"evaluation_type": "evaluation_type",
"id": "value_id",
"system": "system",
"value_type": "value_type",
"value": "value",
"value_unit": "value_unit",
"basis": "basis",
"pod_value": "pod_value",
"pod_unit": "pod_unit",
"species_studied": "species_studied",
"duration": "duration",
"study_id": "study_id",
"study__short_citation": "study_citation",
"confidence": "confidence",
"uncertainty": "uncertainty",
"tumor_type": "tumor_type",
"extrapolation_method": "extrapolation_method",
"evidence": "evidence",
"comments": "comments",
"extra": "extra",
}
data = self.select_related("assessment__details").values_list(*list(mapping.keys()))
df = pd.DataFrame(data=data, columns=list(mapping.values())).sort_values(
["assessment_id", "value_id"]
)
map_enum(df, "project_status", constants.Status, replace=True)
map_enum(df, "peer_review_status", constants.PeerReviewType, replace=True)
map_enum(df, "evaluation_type", constants.EvaluationType, replace=True)
map_enum(df, "value_type", constants.ValueType, replace=True)
map_enum(df, "confidence", constants.Confidence, replace=True)
return df


class AssessmentDetailManager(BaseManager):
assessment_relation = "assessment"
Expand Down
25 changes: 25 additions & 0 deletions hawc/apps/common/api/filters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from django.db.models import QuerySet
from django_filters.filterset import FilterSet
from django_filters.utils import translate_validation
from rest_framework import exceptions, filters
from rest_framework.request import Request

from ..helper import try_parse_list_ints

Expand Down Expand Up @@ -30,3 +34,24 @@ def filter_queryset(self, request, queryset, view):
raise exceptions.PermissionDenied()

return queryset


def filtered_qs(
queryset: QuerySet, filterset_cls: type[FilterSet], request: Request, **kw
) -> QuerySet:
"""
Filter a queryset based on a FilterSet and a DRF request.

This is a utility method to add filtering to custom ViewSet actions, it is adapted from the
`django_filters.rest_framework.FilterSet` used for standard ViewSet operations.

Args:
queryset (QuerySet): the queryset to filter
filterset_cls (type[filters.FilterSet]): a FilterSet class
request (Request): a rest framework request
**kw: any additional arguments provided to FilterSet class constructor
"""
filterset = filterset_cls(data=request.query_params, queryset=queryset, request=request, **kw)
if not filterset.is_valid():
raise translate_validation(filterset.errors)
return filterset.qs
15 changes: 9 additions & 6 deletions hawc/apps/hawc_admin/api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from django.utils import timezone
from rest_framework import permissions, status, viewsets
from rest_framework import permissions, viewsets
from rest_framework.decorators import action
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response

from ..assessment.exports import ValuesListExport
from ..assessment import exports
from ..assessment.filterset import AssessmentValueFilterSet
from ..assessment.models import AssessmentValue
from ..common.api import FivePerMinuteThrottle
from ..common.api.filters import filtered_qs
from ..common.helper import FlatExport
from ..common.renderers import PandasRenderers
from .actions import media_metadata_report
Expand Down Expand Up @@ -40,7 +42,8 @@ class ReportsViewSet(viewsets.ViewSet):
@action(detail=False, renderer_classes=PandasRenderers)
def values(self, request):
"""Gets all value data across all assessments."""
export = ValuesListExport(
queryset=AssessmentValue.objects.all(), filename="hawc-assessment-values"
).build_export()
return Response(export, status=status.HTTP_200_OK)
qs = AssessmentValue.objects.all()
exporter = exports.AssessmentExporter.flat_export(
filtered_qs(qs, AssessmentValueFilterSet, request), filename="assessment-values"
)
return Response(exporter)
2 changes: 1 addition & 1 deletion tests/hawc/apps/hawc_admin/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def test_assessment_values(self):
resp = client.get(url)
assert resp.status_code == 200
df = pd.read_json(StringIO(resp.content.decode()))
assert df.shape == (3, 33)
assert df.shape == (3, 44)


@pytest.mark.django_db
Expand Down