Skip to content

Commit 1df3dd2

Browse files
authored
Merge pull request #21 from cmu-delphi/main
Update development branch
2 parents 630eb67 + 6bd761e commit 1df3dd2

38 files changed

+1874
-21
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.0.7 on 2024-10-15 12:31
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('datasources', '0001_initial'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='datasource',
15+
name='display_name',
16+
field=models.CharField(blank=True, max_length=128, verbose_name='Display Name'),
17+
),
18+
]

src/datasources/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class DataSource(TimeStampedModel):
1616
display_name: models.CharField = models.CharField(
1717
verbose_name=_('Display Name'),
1818
max_length=128,
19+
blank=True
1920
)
2021
description: models.TextField = models.TextField(
2122
verbose_name=_('Description'),

src/signal_documentation/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
'base',
105105
'datasources',
106106
'signals',
107+
'signal_sets',
107108
]
108109

109110
INSTALLED_APPS: list[str] = DEFAULT_APPS + EXTERNAL_APPS + LOCAL_APPS

src/signal_documentation/urls.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020
from django.contrib import admin
2121
from django.urls import include, path
2222

23-
from base.views import (BadRequestErrorView, ForbiddenErrorView,
24-
InternalServerErrorView, NotFoundErrorView)
23+
from base.views import (
24+
BadRequestErrorView,
25+
ForbiddenErrorView,
26+
InternalServerErrorView,
27+
NotFoundErrorView,
28+
)
2529

2630
handler400 = BadRequestErrorView.as_view()
2731
handler403 = ForbiddenErrorView.as_view()
@@ -31,13 +35,19 @@
3135

3236
urlpatterns = [
3337
path(f'{settings.MAIN_PAGE}/admin/' if settings.MAIN_PAGE else 'admin/', admin.site.urls),
38+
# signal_sets
39+
path(
40+
f"{settings.MAIN_PAGE}/" if settings.MAIN_PAGE else "",
41+
include("signal_sets.urls"),
42+
),
3443
# signals
3544
path(
36-
f"{settings.MAIN_PAGE}/" if settings.MAIN_PAGE else "", include("signals.urls")
45+
f"{settings.MAIN_PAGE}/signals/" if settings.MAIN_PAGE else "signals/",
46+
include("signals.urls"),
3747
),
3848
# datasources
3949
path(
40-
f"{settings.MAIN_PAGE}/datasources" if settings.MAIN_PAGE else "datasources",
50+
f"{settings.MAIN_PAGE}/datasources/" if settings.MAIN_PAGE else "datasources",
4151
include("datasources.urls"),
4252
),
4353
path("__debug__/", include("debug_toolbar.urls")),

src/signal_sets/__init__.py

Whitespace-only changes.

src/signal_sets/admin.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.contrib import admin
2+
from import_export.admin import ImportExportModelAdmin
3+
4+
from signal_sets.resources import SignalSetResource
5+
from signal_sets.models import SignalSet
6+
7+
8+
@admin.register(SignalSet)
9+
class SignalSetAdmin(ImportExportModelAdmin):
10+
list_display = ('name', 'data_description', 'maintainer_name', 'maintainer_email', 'organization')
11+
search_fields = ('name', 'maintainer_name', 'maintainer_email', 'organization')
12+
resource_class = SignalSetResource

src/signal_sets/apps.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class SignalSetsConfig(AppConfig):
5+
default_auto_field = 'django.db.models.BigAutoField'
6+
name = 'signal_sets'

src/signal_sets/filters.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import logging
2+
3+
import django_filters
4+
from django_filters.widgets import QueryArrayWidget
5+
6+
from signals.models import Pathogen, GeographicScope, Geography, SeverityPyramidRung
7+
from signal_sets.models import SignalSet
8+
from datasources.models import DataSource
9+
10+
logger = logging.getLogger(__name__)
11+
12+
13+
class SignalSetFilter(django_filters.FilterSet):
14+
15+
pathogens = django_filters.ModelMultipleChoiceFilter(
16+
field_name="pathogens",
17+
queryset=Pathogen.objects.all(),
18+
widget=QueryArrayWidget,
19+
)
20+
21+
geographic_scope = django_filters.ModelMultipleChoiceFilter(
22+
field_name="geographic_scope",
23+
queryset=GeographicScope.objects.all(),
24+
widget=QueryArrayWidget,
25+
)
26+
27+
available_geographies = django_filters.ModelMultipleChoiceFilter(
28+
field_name="available_geographies",
29+
queryset=Geography.objects.all().order_by("display_order_number"),
30+
widget=QueryArrayWidget,
31+
)
32+
33+
severity_pyramid_rungs = django_filters.ModelMultipleChoiceFilter(
34+
field_name="severity_pyramid_rungs",
35+
queryset=SeverityPyramidRung.objects.all(),
36+
widget=QueryArrayWidget,
37+
)
38+
39+
data_source = django_filters.ModelMultipleChoiceFilter(
40+
field_name="data_source",
41+
queryset=DataSource.objects.all(),
42+
widget=QueryArrayWidget,
43+
)
44+
45+
temporal_granularity = django_filters.MultipleChoiceFilter(
46+
field_name="temporal_granularity",
47+
choices=[
48+
("Daily", "Daily"),
49+
("Weekly", "Weekly"),
50+
("Hourly", "Hourly"),
51+
],
52+
lookup_expr="icontains",
53+
)
54+
55+
class Meta:
56+
model = SignalSet
57+
fields: list[str] = [
58+
"pathogens",
59+
"geographic_scope",
60+
"available_geographies",
61+
"severity_pyramid_rungs",
62+
"data_source",
63+
"temporal_granularity"
64+
]

src/signal_sets/forms.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from django import forms
2+
3+
from signals.models import Pathogen, GeographicScope, Geography, SeverityPyramidRung
4+
from signal_sets.models import SignalSet
5+
from datasources.models import DataSource
6+
7+
8+
class SignalSetFilterForm(forms.ModelForm):
9+
10+
pathogens = forms.ModelChoiceField(
11+
queryset=Pathogen.objects.all(), widget=forms.CheckboxSelectMultiple()
12+
)
13+
14+
geographic_scope = forms.ModelChoiceField(
15+
queryset=GeographicScope.objects.all(), widget=forms.CheckboxSelectMultiple()
16+
)
17+
18+
available_geographies = forms.ModelChoiceField(
19+
queryset=Geography.objects.all().order_by("display_order_number"),
20+
widget=forms.CheckboxSelectMultiple(),
21+
)
22+
23+
severity_pyramid_rungs = forms.ModelChoiceField(
24+
queryset=SeverityPyramidRung.objects.all(),
25+
widget=forms.CheckboxSelectMultiple(),
26+
)
27+
28+
data_source = forms.ModelChoiceField(
29+
queryset=DataSource.objects.all(),
30+
widget=forms.CheckboxSelectMultiple(),
31+
)
32+
33+
temporal_granularity = forms.ChoiceField(
34+
choices=[
35+
("Daily", "Daily"),
36+
("Weekly", "Weekly"),
37+
("Hourly", "Hourly"),
38+
],
39+
widget=forms.CheckboxSelectMultiple(),
40+
)
41+
42+
class Meta:
43+
model = SignalSet
44+
fields: list[str] = [
45+
"pathogens",
46+
"geographic_scope",
47+
"available_geographies",
48+
"severity_pyramid_rungs",
49+
"data_source",
50+
"temporal_granularity"
51+
]
52+
53+
def __init__(self, *args, **kwargs) -> None:
54+
"""
55+
Initialize the form.
56+
"""
57+
super().__init__(*args, **kwargs)
58+
59+
# Set required attribute to False and disable helptext for all fields
60+
for field_name, field in self.fields.items():
61+
field.required = False
62+
field.help_text = ""
63+
field.label = ""
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Generated by Django 5.0.7 on 2024-10-07 18:20
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
initial = True
10+
11+
dependencies = [
12+
('datasources', '0001_initial'),
13+
('signals', '0002_auto_20241002_2027'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='SignalSet',
19+
fields=[
20+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('name', models.CharField(max_length=128, unique=True, verbose_name='255')),
22+
('data_description', models.TextField(blank=True, verbose_name='Data Description')),
23+
('maintainer_name', models.CharField(blank=True, max_length=128, verbose_name='Maintainer Name')),
24+
('maintainer_email', models.CharField(blank=True, max_length=128, verbose_name='Maintainer Email')),
25+
('organization', models.CharField(blank=True, max_length=128, verbose_name='Organization')),
26+
('language', models.CharField(blank=True, max_length=128, verbose_name='Language')),
27+
('version_number', models.CharField(blank=True, max_length=128, verbose_name='Version Number')),
28+
('origin_datasource', models.CharField(blank=True, max_length=128, verbose_name='Origin Data Source')),
29+
('data_type', models.CharField(blank=True, max_length=128, verbose_name='Data Type')),
30+
('preprocessing_description', models.CharField(blank=True, max_length=128, verbose_name='Preprocessing Description')),
31+
('temporal_scope_start', models.CharField(help_text='Temporal scope start of the signal set.', max_length=255, verbose_name='temporal scope start')),
32+
('temporal_scope_end', models.CharField(help_text='Temporal scope end of the signal set.', max_length=255, verbose_name='temporal scope end')),
33+
('temporal_granularity', models.CharField(help_text='Temporal granularity of the signal set.', max_length=255, verbose_name='temporal granularity')),
34+
('reporting_cadence', models.CharField(help_text='Reporting cadence of the signal set.', max_length=255, verbose_name='reporting cadence')),
35+
('reporting_lag', models.CharField(help_text='Typical reporting lag of the signal set.', max_length=255, verbose_name='typical reporting lag')),
36+
('revision_cadence', models.CharField(help_text='Revision cadence of the signal set.', max_length=255, verbose_name='revision cadence')),
37+
('demographic_scope', models.CharField(help_text='Demographic scope of the signal set.', max_length=255, verbose_name='demographic scope')),
38+
('demographic_granularity', models.CharField(help_text='Demographic granularity of the signal set.', max_length=255, verbose_name='demographic granularity')),
39+
('censoring', models.CharField(help_text='Data censoring of the signal set.', max_length=255, verbose_name='data censoring')),
40+
('missingness', models.CharField(help_text='Missingness of the signal set.', max_length=255, verbose_name='missingness')),
41+
('dua_required', models.BooleanField(help_text='Whether a data use agreement is required to access the signal set.', verbose_name='DUA Required')),
42+
('license', models.CharField(help_text='License of the signal set.', max_length=255, verbose_name='license')),
43+
('dataset_location', models.CharField(help_text='Location of the dataset.', max_length=255, verbose_name='dataset location')),
44+
('link_to_dictionary', models.CharField(help_text='Link to the dictionary.', max_length=255, verbose_name='link to dictionary')),
45+
('data_source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='datasources.datasource', verbose_name='Data Source')),
46+
('geographic_scope', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='signal_sets', to='signals.geographicscope', verbose_name='Geographic Scope')),
47+
('pathogens', models.ManyToManyField(help_text='Pathogen(s) associated with the signal set.', related_name='signal_sets', to='signals.pathogen', verbose_name='Pathogen')),
48+
('severity_pyramid_rungs', models.ManyToManyField(blank=True, help_text='Severity pyramid rungs of the signal set.', null=True, related_name='signal_sets', to='signals.severitypyramidrung')),
49+
],
50+
options={
51+
'ordering': ['name'],
52+
},
53+
),
54+
migrations.CreateModel(
55+
name='SignalSetGeography',
56+
fields=[
57+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
58+
('aggregated_by_delphi', models.BooleanField(default=False)),
59+
('geography', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='geography_signal_sets', to='signals.geography')),
60+
('signal_set', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='geography_signal_sets', to='signal_sets.signalset')),
61+
],
62+
options={
63+
'verbose_name_plural': 'Signal Geographies',
64+
'unique_together': {('geography', 'signal_set')},
65+
},
66+
),
67+
migrations.AddField(
68+
model_name='signalset',
69+
name='available_geography',
70+
field=models.ManyToManyField(related_name='signal_sets', through='signal_sets.SignalSetGeography', to='signals.geography', verbose_name='Available Geography'),
71+
),
72+
migrations.AlterUniqueTogether(
73+
name='signalset',
74+
unique_together={('name', 'data_source')},
75+
),
76+
]

0 commit comments

Comments
 (0)