forked from City-of-Helsinki/smbackend
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #350 from City-of-Turku/feature/environment-data-r…
…ewrite-api-with-django-filterset Feature/environment data rewrite api with django filterset
- Loading branch information
Showing
4 changed files
with
249 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,127 @@ | ||
from datetime import datetime | ||
|
||
from rest_framework.exceptions import ParseError | ||
|
||
from .constants import DATA_TYPES, DATETIME_FORMATS, DAY, HOUR, MONTH, WEEK, YEAR | ||
|
||
|
||
def validate_timestamp(timestamp_str, data_type): | ||
time_format = DATETIME_FORMATS[data_type] | ||
try: | ||
datetime.strptime(timestamp_str, time_format) | ||
except ValueError: | ||
return f"{timestamp_str} invalid format date format, valid format for type {data_type} is {time_format}" | ||
return None | ||
|
||
|
||
def get_start_and_end_and_year(filters, data_type): | ||
start = filters.get("start", None) | ||
end = filters.get("end", None) | ||
year = filters.get("year", None) | ||
|
||
if not start or not end: | ||
raise ParseError("Supply both 'start' and 'end' parameters") | ||
|
||
if YEAR not in data_type and not year: | ||
raise ParseError("Supply 'year' parameter") | ||
|
||
res1 = None | ||
res2 = None | ||
match data_type: | ||
case DATA_TYPES.DAY: | ||
res1 = validate_timestamp(start, DAY) | ||
res2 = validate_timestamp(end, DAY) | ||
case DATA_TYPES.HOUR: | ||
res1 = validate_timestamp(start, HOUR) | ||
res2 = validate_timestamp(end, HOUR) | ||
case DATA_TYPES.WEEK: | ||
res1 = validate_timestamp(start, WEEK) | ||
res2 = validate_timestamp(end, WEEK) | ||
case DATA_TYPES.MONTH: | ||
res1 = validate_timestamp(start, MONTH) | ||
res2 = validate_timestamp(end, MONTH) | ||
case DATA_TYPES.YEAR: | ||
res1 = validate_timestamp(start, YEAR) | ||
res2 = validate_timestamp(end, YEAR) | ||
|
||
if res1: | ||
raise ParseError(res1) | ||
if res2: | ||
raise ParseError(res2) | ||
|
||
if HOUR in data_type or DAY in data_type: | ||
start = f"{year}-{start}" | ||
end = f"{year}-{end}" | ||
return start, end, year | ||
import django_filters | ||
|
||
from environment_data.models import ( | ||
DayData, | ||
HourData, | ||
MonthData, | ||
Station, | ||
WeekData, | ||
YearData, | ||
) | ||
|
||
|
||
class StationFilterSet(django_filters.FilterSet): | ||
geo_id = django_filters.NumberFilter(field_name="geo_id", lookup_expr="exact") | ||
name = django_filters.CharFilter(lookup_expr="icontains") | ||
|
||
class Meta: | ||
model = Station | ||
fields = {"data_type": ["exact"]} | ||
|
||
|
||
class BaseFilterSet(django_filters.FilterSet): | ||
|
||
station_id = django_filters.NumberFilter(field_name="station") | ||
|
||
class Meta: | ||
fields = {"station": ["exact"]} | ||
|
||
def get_date(self, year_number, month_and_day): | ||
return f"{year_number}-{month_and_day}" | ||
|
||
|
||
class YearDataFilterSet(django_filters.FilterSet): | ||
station_id = django_filters.NumberFilter(field_name="station") | ||
start = django_filters.NumberFilter( | ||
field_name="year__year_number", lookup_expr="gte" | ||
) | ||
end = django_filters.NumberFilter(field_name="year__year_number", lookup_expr="lte") | ||
|
||
class Meta: | ||
model = YearData | ||
fields = {"station": ["exact"]} | ||
|
||
|
||
class MonthDataFilterSet(BaseFilterSet): | ||
def filter_year(self, queryset, field, year): | ||
return queryset.filter(month__year__year_number=year) | ||
|
||
year = django_filters.NumberFilter(method="filter_year") | ||
start = django_filters.NumberFilter( | ||
field_name="month__month_number", lookup_expr="gte" | ||
) | ||
end = django_filters.NumberFilter( | ||
field_name="month__month_number", lookup_expr="lte" | ||
) | ||
|
||
class Meta: | ||
model = MonthData | ||
fields = BaseFilterSet.Meta.fields | ||
|
||
|
||
class WeekDataFilterSet(BaseFilterSet): | ||
def filter_year(self, queryset, field, year): | ||
return queryset.filter(week__years__year_number=year) | ||
|
||
year = django_filters.NumberFilter(method="filter_year") | ||
start = django_filters.NumberFilter( | ||
field_name="week__week_number", lookup_expr="gte" | ||
) | ||
end = django_filters.NumberFilter(field_name="week__week_number", lookup_expr="lte") | ||
|
||
class Meta: | ||
model = WeekData | ||
fields = BaseFilterSet.Meta.fields | ||
|
||
|
||
class DateDataFilterSet(BaseFilterSet): | ||
DATE_MODEL_NAME = None | ||
YEAR_LOOKUP = None | ||
|
||
def filter_year(self, queryset, field, year): | ||
return queryset.filter(**{f"{self.DATE_MODEL_NAME}__year__year_number": year}) | ||
|
||
def filter_start(self, queryset, field, start): | ||
first = queryset.first() | ||
if first: | ||
lookup = first | ||
if self.YEAR_LOOKUP: | ||
lookup = getattr(first, self.YEAR_LOOKUP) | ||
date = self.get_date(lookup.day.year.year_number, start) | ||
return queryset.filter(**{f"{self.DATE_MODEL_NAME}__date__gte": date}) | ||
else: | ||
return queryset.none() | ||
|
||
def filter_end(self, queryset, field, end): | ||
first = queryset.first() | ||
if first: | ||
lookup = first | ||
if self.YEAR_LOOKUP: | ||
lookup = getattr(first, self.YEAR_LOOKUP) | ||
date = self.get_date(lookup.day.year.year_number, end) | ||
return queryset.filter(**{f"{self.DATE_MODEL_NAME}__date__lte": date}) | ||
else: | ||
return queryset.none() | ||
|
||
year = django_filters.NumberFilter(method="filter_year") | ||
start = django_filters.CharFilter(method="filter_start") | ||
end = django_filters.CharFilter(method="filter_end") | ||
|
||
|
||
class DayDataFilterSet(DateDataFilterSet): | ||
|
||
DATE_MODEL_NAME = "day" | ||
|
||
class Meta: | ||
model = DayData | ||
fields = BaseFilterSet.Meta.fields | ||
|
||
|
||
class HourDataFilterSet(DateDataFilterSet): | ||
|
||
DATE_MODEL_NAME = "hour__day" | ||
YEAR_LOOKUP = "hour" | ||
|
||
class Meta: | ||
model = HourData | ||
fields = BaseFilterSet.Meta.fields |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.