Skip to content

Commit 9d8e47b

Browse files
committed
Added models for DemographicScope and DemographicScopeAdmin in admin.py
1 parent 098c2bd commit 9d8e47b

File tree

4 files changed

+103
-13
lines changed

4 files changed

+103
-13
lines changed

docker-compose.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ services:
3535
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/pathogens.json &&
3636
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/signal_types.json &&
3737
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/signal_categories.json &&
38+
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/demographic_scopes.json &&
3839
python3 /usr/src/signal_documentation/src/manage.py runserver 0.0.0.0:8000"
3940
volumes:
4041
- .:/usr/src/signal_documentation
@@ -49,7 +50,7 @@ services:
4950
restart: always
5051
ports:
5152
- "6379:6379"
52-
53+
5354
# Production service - "service", "image", and "container_name" should all contain the same
5455
# reference, based on the name of the service.
5556
sdnginx:

src/fixtures/demographic_scopes.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
{
3+
"model": "signals.DemographicScope",
4+
"pk": 1,
5+
"fields": {
6+
"name": "nationwide Change Healthcare network"
7+
}
8+
},
9+
{
10+
"model": "signals.DemographicScope",
11+
"pk": 2,
12+
"fields": {
13+
"name": "nationwide Optum network"
14+
}
15+
},
16+
{
17+
"model": "signals.DemographicScope",
18+
"pk": 3,
19+
"fields": {
20+
"name": "Adult Facebook users"
21+
}
22+
},
23+
{
24+
"model": "signals.DemographicScope",
25+
"pk": 4,
26+
"fields": {
27+
"name": "Google search users"
28+
}
29+
},
30+
{
31+
"model": "signals.DemographicScope",
32+
"pk": 5,
33+
"fields": {
34+
"name": "Smartphone users"
35+
}
36+
}
37+
]

src/signals/admin.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from import_export.admin import ImportExportModelAdmin
55

66
from signals.models import (
7+
DemographicScope,
78
Geography,
89
Pathogen,
910
Signal,
@@ -49,6 +50,15 @@ class SignalTypeAdmin(admin.ModelAdmin):
4950
search_fields: tuple[Literal['name']] = ('name',)
5051

5152

53+
@admin.register(DemographicScope)
54+
class DemographicScopeAdmin(admin.ModelAdmin):
55+
"""
56+
Admin interface for managing demographic scope objects.
57+
"""
58+
list_display: tuple[Literal['name']] = ('name',)
59+
search_fields: tuple[Literal['name']] = ('name',)
60+
61+
5262
@admin.register(Signal)
5363
class SignalAdmin(ImportExportModelAdmin):
5464
"""

src/signals/models.py

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,27 @@ class ActiveChoices(models.TextChoices):
5757
HISTORICAL = False, _('Historical')
5858

5959

60-
class DemograohicDisaggregation(models.TextChoices):
60+
class SeverityPyramidRungsChoices(models.TextChoices):
6161
"""
62-
A class representing choices for demographic disaggregation.
62+
A class representing choices for severity pyramid rungs.
6363
"""
64-
pass # TODO: Add choices for demographic disaggregation or split into separate classes if needed. Should be discussed.
64+
POPULATION = 'population', _('Population')
65+
INFECTED = 'infected', _('Infected')
66+
SYMPTOMATIC = 'symptomatic', _('Symptomatic')
67+
OUTPATIENT_VISIT = 'outpatient_visit', _('Outpatient visit')
68+
ASCERTAINED = 'ascertained', _('Ascertained (case)')
69+
HOSPITALIZED = 'hospitalized', _('Hospitalized')
70+
ICU = 'icu', _('ICU')
71+
DEAD = 'dead', _('Dead')
72+
73+
74+
class AgeBreakdownChoices(models.TextChoices):
75+
"""
76+
A class representing choices for age breakdown.
77+
"""
78+
CILDREN = '0-17', '0-17'
79+
ADULTS = '18-64', '18-64'
80+
SENIORS = '65+', '65+'
6581

6682

6783
class SignalCategory(TimeStampedModel):
@@ -152,7 +168,7 @@ def __str__(self) -> str:
152168
return str(self.name)
153169

154170

155-
class GeographicScope(TimeStampedModel): # TODO: Requirements for this model are not clear. Need to be discussed.
171+
class GeographicScope(TimeStampedModel):
156172
"""
157173
A model representing a geographic scope.
158174
"""
@@ -172,7 +188,7 @@ def __str__(self) -> str:
172188
return str(self.name)
173189

174190

175-
class DemograficScope(TimeStampedModel):
191+
class DemographicScope(TimeStampedModel):
176192
"""
177193
A model representing a demographic scope.
178194
"""
@@ -192,13 +208,14 @@ def __str__(self) -> str:
192208
return str(self.name)
193209

194210

195-
class OrganisationsAccess(TimeStampedModel): # TODO: Requirements for this model are not clear. Need to be discussed.
211+
class OrganisationsWithAccess(TimeStampedModel): # TODO: Requirements for this model are not clear. Need to be discussed.
196212
"""
197213
A model representing an access list.
198214
"""
199215
organisation_name: models.CharField = models.CharField(
200216
help_text=_('Organisation Name'),
201217
max_length=128,
218+
unique=True
202219
)
203220

204221

@@ -209,6 +226,7 @@ class SharingOrganisation(TimeStampedModel): # TODO: Requirements for this mode
209226
organisation_name: models.CharField = models.CharField(
210227
help_text=_('Organisation Name'),
211228
max_length=128,
229+
unique=True
212230
)
213231

214232

@@ -279,14 +297,14 @@ class Signal(TimeStampedModel):
279297
choices=ReportingCadence.choices
280298
)
281299
demographic_scope: models.ManyToManyField = models.ManyToManyField(
282-
'signals.DemograficScope',
300+
'signals.DemographicScope',
301+
help_text=_('Demographic Scope'),
283302
related_name='signals',
284-
help_text=_('Demographic Scope')
285303
)
286-
demographic_disaggregation: models.CharField = models.CharField( # TODO: Choices for this field are not clear. Need to be discussed.
287-
help_text=_('Demographic Disaggregation'),
304+
severenity_pyramid_rungs: models.CharField = models.CharField(
305+
help_text=_('Severity Pyramid Rungs'),
288306
max_length=128,
289-
choices=DemograohicDisaggregation.choices
307+
choices=SeverityPyramidRungsChoices.choices
290308
)
291309
category: models.ForeignKey = models.ForeignKey(
292310
'signals.SignalCategory',
@@ -304,6 +322,20 @@ class Signal(TimeStampedModel):
304322
'signals.Geography',
305323
help_text=_('Available geography')
306324
)
325+
gender_breakdown: models.BooleanField = models.BooleanField(
326+
help_text=_('Gender Breakdown'),
327+
default=False
328+
)
329+
race_breakdown: models.BooleanField = models.BooleanField(
330+
help_text=_('Race Breakdown'),
331+
default=False,
332+
)
333+
age_breakdown: models.CharField = models.CharField(
334+
help_text=_('Age Breakdown'),
335+
max_length=128,
336+
choices=AgeBreakdownChoices.choices,
337+
null=True,
338+
)
307339
is_smoothed: models.BooleanField = models.BooleanField(
308340
help_text=_('Is Smoothed'),
309341
default=False
@@ -372,10 +404,20 @@ class Signal(TimeStampedModel):
372404
)
373405

374406
@property
375-
def example_url(self):
407+
def example_url(self) -> str | None:
408+
"""
409+
Returns the example URL of the signal.
410+
"""
376411
example_url = self.links.filter(link_type="example_url").first()
377412
return example_url.url if example_url else None
378413

414+
@property
415+
def has_all_demographic_scopes(self) -> bool:
416+
"""
417+
Returns True if the signal has all demographic scopes, False otherwise.
418+
"""
419+
return self.demographic_scope.count() == DemographicScope.objects.count()
420+
379421
class Meta:
380422
unique_together = ['name', 'source']
381423
ordering: list[str] = ["modified"]

0 commit comments

Comments
 (0)