Skip to content

Commit

Permalink
Merge pull request #345 from City-of-Turku/develop
Browse files Browse the repository at this point in the history
Production update
  • Loading branch information
juuso-j committed Apr 15, 2024
2 parents 8108054 + 69282d5 commit fbb49bf
Show file tree
Hide file tree
Showing 36 changed files with 1,306 additions and 35 deletions.
10 changes: 9 additions & 1 deletion eco_counter/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,16 @@ def get_date(self, obj):


class ImportStateAdmin(admin.ModelAdmin):
list_display = (
"id",
"csv_data_source",
"current_year_number",
"current_month_number",
"current_day_number",
)

def get_readonly_fields(self, request, obj=None):
return [f.name for f in self.model._meta.fields]
return ["csv_data_source"]


class StationAdmin(admin.ModelAdmin):
Expand Down
3 changes: 2 additions & 1 deletion eco_counter/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import platform
import types
from datetime import datetime

import requests
from django.conf import settings
Expand All @@ -12,7 +13,7 @@
# Manually define the end year, as the source data comes from the page
# defined in env variable TRAFFIC_COUNTER_OBSERVATIONS_BASE_URL.
# Change end year when data for the next year is available.
TRAFFIC_COUNTER_END_YEAR = 2023
TRAFFIC_COUNTER_END_YEAR = datetime.today().year
ECO_COUNTER_START_YEAR = 2020
LAM_COUNTER_START_YEAR = 2010
TELRAAM_COUNTER_START_YEAR = 2023
Expand Down
5 changes: 4 additions & 1 deletion eco_counter/management/commands/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,10 @@ def get_traffic_counter_csv(start_year=2015):
# data from years before the start year.
if key <= start_year:
continue
concat_df = get_dataframe(TRAFFIC_COUNTER_CSV_URLS[key])
try:
concat_df = get_dataframe(TRAFFIC_COUNTER_CSV_URLS[key])
except AssertionError:
continue
# ignore_index=True, do not use the index values along the concatenation axis.
# The resulting axis will be labeled 0, …, n - 1.
df = pd.concat([df, concat_df], ignore_index=True)
Expand Down
15 changes: 15 additions & 0 deletions exceptional_situations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Exceptional Situations APP
APP for importing, storing and serving exceptional situations

## Importing data
### Traffic Announcements
Imports road works and traffic announcements in Southwest Finland from digitraffic.fi.
To import type:
`./manage.py import_traffic_situations`

### Delete inactive situations
`./manage.py delete_inactive_situations`
Deletes also the related announcements and locations.

## API Documentation
See online swagger documentation.
Empty file.
33 changes: 33 additions & 0 deletions exceptional_situations/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from django.contrib.gis import admin

from exceptional_situations.models import (
Situation,
SituationAnnouncement,
SituationLocation,
SituationType,
)


class SituationAdmin(admin.ModelAdmin):
list_display = ("is_active", "start_time", "end_time")


class SituationTypeAdmin(admin.ModelAdmin):
list_display = ("type_name", "sub_type_name")


class SituationAnnouncementAdmin(admin.ModelAdmin):
list_display = ("title", "start_time", "end_time")


class SituationLocationAdmin(admin.OSMGeoAdmin):
list_display = ("id", "title", "geometry")

def title(self, obj):
return obj.announcement.title


admin.site.register(Situation, SituationAdmin)
admin.site.register(SituationType, SituationTypeAdmin)
admin.site.register(SituationAnnouncement, SituationAnnouncementAdmin)
admin.site.register(SituationLocation, SituationLocationAdmin)
58 changes: 58 additions & 0 deletions exceptional_situations/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from rest_framework import serializers

from exceptional_situations.models import (
Situation,
SituationAnnouncement,
SituationLocation,
SituationType,
)


class SituationLocationSerializer(serializers.ModelSerializer):
class Meta:
model = SituationLocation
fields = ["id", "location", "geometry", "details"]


class SituationAnnouncementSerializer(serializers.ModelSerializer):
location = SituationLocationSerializer()

class Meta:
model = SituationAnnouncement
fields = [
"id",
"title",
"description",
"start_time",
"end_time",
"additional_info",
"location",
]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)


class SituationTypeSerializer(serializers.ModelSerializer):
class Meta:
model = SituationType
fields = "__all__"


class SituationSerializer(serializers.ModelSerializer):
announcements = SituationAnnouncementSerializer(many=True, read_only=True)

class Meta:
model = Situation
fields = [
"id",
"is_active",
"start_time",
"end_time",
"situation_id",
"release_time",
"situation_type",
"situation_type_str",
"situation_sub_type_str",
"announcements",
]
24 changes: 24 additions & 0 deletions exceptional_situations/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.urls import include, path
from rest_framework import routers

from exceptional_situations.api import views

app_name = "exceptional_situations"


router = routers.DefaultRouter()

router.register("situation", views.SituationViewSet, basename="situation")
router.register("situation_type", views.SituationTypeViewSet, basename="situation_type")
router.register(
"situation_location", views.SituationLocationViewSet, basename="situation_location"
)
router.register(
"situation_announcement",
views.SituationAnnouncementViewSet,
basename="situation_announcement",
)

urlpatterns = [
path("api/v1/", include(router.urls), name="exceptional_situations"),
]
87 changes: 87 additions & 0 deletions exceptional_situations/api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import django_filters
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets

from exceptional_situations.api.serializers import (
SituationAnnouncementSerializer,
SituationLocationSerializer,
SituationSerializer,
SituationTypeSerializer,
)
from exceptional_situations.models import (
Situation,
SituationAnnouncement,
SituationLocation,
SituationType,
)


class SituationFilter(django_filters.FilterSet):
is_active = django_filters.BooleanFilter(method="filter_is_active")
situation_type_str = django_filters.CharFilter(method="filter_situation_type_str")
start_time__gt = django_filters.DateTimeFilter(method="filter_start_time__gt")
start_time__lt = django_filters.DateTimeFilter(method="filter_start_time__lt")
end_time__gt = django_filters.DateTimeFilter(method="filter_end_time__gt")
end_time__lt = django_filters.DateTimeFilter(method="filter_end_time__lt")

class Meta:
model = Situation
fields = {
"situation_type": ["exact"],
"situation_id": ["exact"],
"release_time": ["lt", "gt"],
}

def filter_situation_type_str(self, queryset, fields, situation_type_str):
ids = [
obj.id for obj in queryset if obj.situation_type_str == situation_type_str
]
return queryset.filter(id__in=ids)

def filter_is_active(self, queryset, fields, active):
ids = [obj.id for obj in queryset if obj.is_active == bool(active)]
return queryset.filter(id__in=ids)

def filter_start_time__gt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time > start_time]
return queryset.filter(id__in=ids)

def filter_start_time__lt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time < start_time]
return queryset.filter(id__in=ids)

def filter_end_time__gt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time > start_time]
return queryset.filter(id__in=ids)

def filter_end_time__lt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time < start_time]
return queryset.filter(id__in=ids)


class SituationViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Situation.objects.all()
serializer_class = SituationSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = SituationFilter

def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.queryset)
page = self.paginate_queryset(queryset)
serializer = self.serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)


class SituationLocationViewSet(viewsets.ReadOnlyModelViewSet):
queryset = SituationLocation.objects.all()
serializer_class = SituationLocationSerializer


class SituationAnnouncementViewSet(viewsets.ReadOnlyModelViewSet):
queryset = SituationAnnouncement.objects.all()
serializer_class = SituationAnnouncementSerializer


class SituationTypeViewSet(viewsets.ReadOnlyModelViewSet):
queryset = SituationType.objects.all()
serializer_class = SituationTypeSerializer
6 changes: 6 additions & 0 deletions exceptional_situations/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ExceptionalSituationsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "exceptional_situations"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import logging

from django.core.management import BaseCommand

from exceptional_situations.models import Situation, SituationAnnouncement

logger = logging.getLogger(__name__)


class Command(BaseCommand):
def handle(self, *args, **options):
num_deleted = 0
for situation in Situation.objects.all():
if situation.is_active is False:
SituationAnnouncement.objects.filter(situation=situation).delete()
situation.delete()
num_deleted += 1
logger.info(f"Deleted {num_deleted} inactive situations.")
Loading

0 comments on commit fbb49bf

Please sign in to comment.