Skip to content

Merge development into staging #164

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

Merged
merged 81 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
32daa00
🛠️ models.py -> Added ReportingCadence for reporting cadences.
BrainIsDead Apr 8, 2024
09d03dc
Merge branch 'development' of https://github.com/cmu-delphi/signal_do…
BrainIsDead Apr 8, 2024
098c2bd
🛠️ models.py -> Added choices for demographic disaggregation.
BrainIsDead Apr 11, 2024
9d8e47b
Added models for DemographicScope and DemographicScopeAdmin in admin.py
BrainIsDead Apr 26, 2024
4d78314
🛠️ src/fixtures/demographic_scopes.json -> Added created and modified…
BrainIsDead Apr 26, 2024
164d1f9
🛠️ models.py -> Modified GeographicScope model with a TODO comment.
BrainIsDead Apr 26, 2024
c25deac
Added hotfix to fix Time Type dropdown & tooltips.
dmytrotsko Jun 3, 2024
9642872
Merge pull request #135 from cmu-delphi/hotfix
dmytrotsko Jun 3, 2024
e3289e7
Add main and staging branches
korlaxxalrok Jun 4, 2024
12c5bb1
Updates to workflow description
korlaxxalrok Jun 4, 2024
16815d0
🛠️ src/datasources/admin.py -> Removed unused tuple
BrainIsDead Jun 5, 2024
cd5118d
🛠️ src/templates/signals/signals.html -> Updated data source display
BrainIsDead Jun 5, 2024
f0d8ff3
Merge pull request #136 from cmu-delphi/update-ci-build-and-deploy
korlaxxalrok Jun 5, 2024
4c2b552
Merge pull request #137 from cmu-delphi/OKRS24-214-Update-SourceSubdi…
BrainIsDead Jun 5, 2024
56add41
Merge branch 'development' of https://github.com/cmu-delphi/signal_do…
BrainIsDead Jun 6, 2024
2a83b16
chore: Add available_geography field to Signal model and update Forei…
BrainIsDead Jun 6, 2024
0af52b1
Update settings.py
dmytrotsko Jun 7, 2024
1f38766
Merge pull request #138 from cmu-delphi/dmytrotsko-patch-7
dmytrotsko Jun 7, 2024
a020fd4
Fixed import, added some missing fields parsing. Fixed available_geog…
dmytrotsko Jun 7, 2024
db32c13
Fixed geographic scope during singals import.
dmytrotsko Jun 10, 2024
6c82ce5
Merge pull request #98 from cmu-delphi/OKRS24-115-Add-new-fields-to-t…
dmytrotsko Jun 10, 2024
0a8ac7d
OKRS24-218 Changed Signal List View table. Added new columns.
dmytrotsko Jun 10, 2024
cc4b0aa
Merge pull request #139 from cmu-delphi/OKRS24-218
dmytrotsko Jun 10, 2024
d335547
Merge pull request #140 from cmu-delphi/pre-development
dmytrotsko Jun 10, 2024
f4d7f26
OKRS24-217 Save stage commit
dmytrotsko Jun 10, 2024
32879df
OKRS24-217 Updated filters.
dmytrotsko Jun 11, 2024
77885ab
Merge pull request #141 from cmu-delphi/OKRS24-217
dmytrotsko Jun 11, 2024
157a7df
Merge pull request #142 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
3f5e5e8
updated docker-compose file.
dmytrotsko Jun 11, 2024
285c8a0
Merge pull request #143 from cmu-delphi/update_docker_compose
dmytrotsko Jun 11, 2024
f56fb19
Added typical_reporting_lag to the list of SignalResource Meta fields.
dmytrotsko Jun 11, 2024
8ce03d7
Merge pull request #144 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
fe93ccd
Added missing fields into resources.py files.
dmytrotsko Jun 11, 2024
64f201a
Merge pull request #145 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
c09c8da
Added missing fields into resources.py files.
dmytrotsko Jun 11, 2024
cde0f4e
Merge pull request #146 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
c6b19a8
Added missing fields into resources.py files.
dmytrotsko Jun 11, 2024
a281f11
Merge pull request #147 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
82e1f58
Added missing fields into resources.py files.
dmytrotsko Jun 11, 2024
4627641
Merge pull request #148 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
282265b
Added DoesNotExist handling.
dmytrotsko Jun 11, 2024
25cff71
Removed base_signal filter.
dmytrotsko Jun 11, 2024
55a9c08
Updated Geography display names.
dmytrotsko Jun 11, 2024
fcac7a8
Added Geo-Level ordering in filters list
dmytrotsko Jun 11, 2024
bafb2aa
Merge pull request #149 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
391400e
Renamed Outpatient Visit -> Outpatient / ED
dmytrotsko Jun 11, 2024
0f31332
Merge pull request #150 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
275e8b8
Moved Country filter above Geo Level. Added Geographic Scope to the a…
dmytrotsko Jun 11, 2024
07f329d
Merge pull request #151 from cmu-delphi/pre-development
dmytrotsko Jun 11, 2024
ac2a5fc
Changed tooltips titles.
dmytrotsko Jun 12, 2024
c2753fc
Updated tooltips
dmytrotsko Jun 12, 2024
42921d5
Added 'Signals With The Same Base' table to the Signal Detailed View.
dmytrotsko Jun 12, 2024
d961097
Minor naming adjustments.
dmytrotsko Jun 12, 2024
6e19364
Merge pull request #152 from cmu-delphi/pre-development
dmytrotsko Jun 13, 2024
e4dcc69
🛠️ forms.py -> Modified source field to use MultipleChoiceField with …
Jun 13, 2024
c79fc12
Merge pull request #153 from cmu-delphi/OKRS24-220
dmytrotsko Jun 13, 2024
ac23ed5
OKRS24-221 Fixed data visualisation section.
dmytrotsko Jun 14, 2024
7395e09
Merge pull request #154 from cmu-delphi/OKRS24-221
dmytrotsko Jun 14, 2024
4cf46e3
🛠️ forms.py -> Updated source field choices
Jun 14, 2024
822cb18
OKRS24-222 Fixed responsiveness in 'Signals with the same base' table.
dmytrotsko Jun 17, 2024
93f1e64
Merge pull request #156 from cmu-delphi/OKRS24-222
dmytrotsko Jun 17, 2024
75b05f2
OKRS24-220 Fixed Data Source filter.
dmytrotsko Jun 17, 2024
ca06d22
Merge pull request #155 from cmu-delphi/OKRS24-220
dmytrotsko Jun 17, 2024
9154e1a
Updates the Nginx location block to work properly when we set `MAIN_P…
korlaxxalrok Jun 18, 2024
3d134a1
Updates the README to include some notes about testing the Nginx prox…
korlaxxalrok Jun 18, 2024
f60d64f
Update README
korlaxxalrok Jun 18, 2024
c5ead64
OKRS24-224 Fixed 'SourceSubdivision' table does not exist on the fres…
dmytrotsko Jun 19, 2024
2eda562
Merge pull request #158 from cmu-delphi/OKRS24-224
dmytrotsko Jun 19, 2024
cf27fa7
Fixed 'Data Source' filter.
dmytrotsko Jun 19, 2024
8b02fe8
Merge pull request #159 from cmu-delphi/data_source_filter_fix
dmytrotsko Jun 19, 2024
5d25c4a
Merge pull request #157 from cmu-delphi/update-nginx-proxy-config
korlaxxalrok Jun 20, 2024
21c54cf
OKRS24-223 Fixed Celery taks to get weekly based dates properly. Adde…
dmytrotsko Jun 20, 2024
b06f4ee
use api.delphi.cmu.edu instead of api.covidcast
melange396 Jun 20, 2024
c4fcf67
Added new env variable 'COVIDCAST_URL' to the settings.py
dmytrotsko Jun 25, 2024
c390176
Merge pull request #161 from cmu-delphi/api_host_rename
dmytrotsko Jun 25, 2024
64a98d3
Merge pull request #160 from cmu-delphi/OKRS24-223
dmytrotsko Jun 25, 2024
d9f8da6
OKRS24-235 Added caching.
dmytrotsko Jun 27, 2024
77c5a3f
OKRS24-235 Added eager loading to reduce number of database calls.
dmytrotsko Jun 27, 2024
d6489dd
Merge pull request #162 from cmu-delphi/OKRS24-235
dmytrotsko Jun 27, 2024
f2a88e8
Use main instead of master
korlaxxalrok Jul 9, 2024
7b88f25
Merge pull request #163 from cmu-delphi/set-up-main-branch-ci
korlaxxalrok Jul 10, 2024
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
5 changes: 3 additions & 2 deletions .github/workflows/build-and-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ jobs:
runs-on: ubuntu-latest
# CI/CD will run on these branches
if: >
github.ref == 'refs/heads/master' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/staging' ||
github.ref == 'refs/heads/development'
strategy:
matrix:
Expand All @@ -27,7 +28,7 @@ jobs:
baseRef="${GITHUB_REF#*/}"
baseRef="${baseRef#*/}"
case "${baseRef}" in
master)
main)
image_tag="latest"
;;
*)
Expand Down
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,14 @@ Open `http://localhost:8000` to view it in the browser
Though probably not necessary in most cases, if you want to test/modify/emulate how this will run in production you can:

- In `.env` set:
```

```shell
DEBUG = 'False'
```

- Modify the app container's command in `docker-compose.yaml` to run:
```

```shell
gunicorn signal_documentation.wsgi:application --bind 0.0.0.0:8000"

*(Essentially you'll replace just the last line of the command, switching out the "runserver" line)
Expand All @@ -96,6 +99,10 @@ Open `http://localhost` to view it in the browser. In this usage your request wi

The primary use case for this will be when making changes to the Nginx container image that runs in production and hosts the static file content, or also if making changes to the Gunicorn config.

Additionally, though again not required for local development, you can also specify an env var of `MAIN_PAGE = $name`, and the app will be served at `http://localhost:8000/$name` (if running in debug mode), or if you've set `DEBUG = 'False'` to run it in Nginx/production mode at `http://localhost/$name/`. Note the ending slash when in Nginx/production mode _and_ using the `MAIN_PAGE` env var.

The primary use case is so that we have flexibility to serve the application at something other than the "bare" URL, though doing this is not necessary for local development.

Changes of this sort should be carefully evaluated as they may require interaction with systems managed by devops folks.

## [Django admin](https://docs.djangoproject.com/en/4.1/ref/contrib/admin/) web interface (user should be `is_staff` or `is_superuser`)
Expand Down Expand Up @@ -200,9 +207,15 @@ Each environment is essentially a bunch of different services all governed by `d

### Basic workflow

- A PR merged to either `development` or `master` will trigger CI to build container images that are then tagged (based on the branch name and ":latest" respectively) and stored in our GitHub Packages container image repository.
- A PR merged to either `development`, `staging`, or `main` will trigger CI to build container images that are then tagged with the branch name (or ":latest", in the cast of `main`), and stored in our GitHub Packages container image repository.
- CI triggers a webhook that tells the host systems to pull and run new container images and restart any services that have been updated.

As a developer, your path to getting changes into production should be something like this:

- Source your working branch from `development`, do work, PR and merge when complete
- PR and merge to `staging` in order to get your changes deployed to https://staging.delphi.cmu.edu/signals for review
- PR and merge to `main` to go to production

**IMPORTANT!** - The CI/CD process uses Docker Compose to build the specific container images that will be used in external environments. Success of the the build-and-deploy workflow is dependent on constructed services in `docker-compose.yaml`. If considering making changes there, please have a PR reviewed by devops folks :pray: :pray: :pray:

### Control of the deployed environment
Expand Down
10 changes: 1 addition & 9 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,7 @@ services:
restart: on-failure
command: sh -c "python3 /usr/src/signal_documentation/src/manage.py migrate --noinput &&
python3 /usr/src/signal_documentation/src/manage.py collectstatic --noinput &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/available_geography.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/pathogens.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/signal_types.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/signal_categories.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/county.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/hhs.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/hrr.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/msa.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/state.json &&
python3 /usr/src/signal_documentation/src/manage.py loaddata ./fixtures/* &&
python3 /usr/src/signal_documentation/src/manage.py runserver 0.0.0.0:8000"
volumes:
- .:/usr/src/signal_documentation
Expand Down
5 changes: 2 additions & 3 deletions nginx/default.conf.template
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
server {
listen 80;
server_name sdnginx;

location /static/ {
location ~* /static/(.*)$ {
autoindex on;
alias /staticfiles/;
alias /staticfiles/$1;
}

location / {
Expand Down
12 changes: 11 additions & 1 deletion src/base/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
DescriptedFilter,
DescriptedFilterField,
Link,
License
)


class DescriptedFilterFieldInline(admin.TabularInline):
model = DescriptedFilterField
fields = ('description',)
fields = ('description', 'filter_field')
extra = 0
can_create = False

Expand All @@ -27,3 +28,12 @@ class LinkAdmin(admin.ModelAdmin):
Admin interface for managing link objects.
"""
list_display: tuple[Literal['url'], Literal['link_type']] = ('url', 'link_type')


@admin.register(License)
class GeographyAdmin(admin.ModelAdmin):
"""
Admin interface for managing license objects.
"""
list_display: tuple[Literal['name'], Literal['use_restrictions']] = ('name', 'use_restrictions')
search_fields: tuple[Literal['name']] = ('name',)
21 changes: 21 additions & 0 deletions src/base/migrations/0004_license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.10 on 2024-06-07 12:15

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('base', '0003_descriptedfilter_alter_link_link_type_and_more'),
]

operations = [
migrations.CreateModel(
name='License',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='License', max_length=256, unique=True)),
('use_restrictions', models.TextField(blank=True, help_text='Use Restrictions', null=True)),
],
),
]
17 changes: 17 additions & 0 deletions src/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,20 @@ def get_preview(self) -> LinkPreview:
return {
'description': _('No description available'),
}


class License(models.Model):
"""
A model representing a License.
"""
name: models.CharField = models.CharField(help_text=_('License'), max_length=256, unique=True)
use_restrictions: models.TextField = models.TextField(help_text=_('Use Restrictions'), blank=True, null=True)

def __str__(self) -> str:
"""
Returns the name of the license as a string.

:return: The name of the license as a string.
:rtype: str
"""
return self.name
5 changes: 1 addition & 4 deletions src/datasources/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ class SourceSubdivisionAdmin(ImportExportModelAdmin):
"""
Admin interface for managing source subdivision objects.
"""
list_display: tuple[Literal['name'], Literal['db_source']] = ('name', 'db_source')
list_display: tuple[Literal['name'], Literal['db_source'], Literal['external_name']] = ('name', 'db_source', 'external_name')
search_fields: tuple[Literal['name'], Literal['db_source']] = ('name', 'db_source')
resource_classes: list[type[SourceSubdivisionResource]] = [SourceSubdivisionResource]


data_source_search_fields_type = tuple[Literal['name'], Literal['source_subdivision__db_source'], Literal['source_subdivision__name'], Literal['description']]


@admin.register(DataSource)
class DataSourceAdmin(ImportExportModelAdmin):
"""
Expand Down
18 changes: 18 additions & 0 deletions src/datasources/migrations/0005_sourcesubdivision_external_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.3 on 2024-06-05 10:09

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('datasources', '0004_alter_datasource_options_and_more'),
]

operations = [
migrations.AddField(
model_name='sourcesubdivision',
name='external_name',
field=models.CharField(help_text='External Name', max_length=128, null=True),
),
]
20 changes: 20 additions & 0 deletions src/datasources/migrations/0006_alter_datasource_source_license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.10 on 2024-06-07 12:15

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('base', '0004_license'),
('datasources', '0005_sourcesubdivision_external_name'),
]

operations = [
migrations.AlterField(
model_name='datasource',
name='source_license',
field=models.ForeignKey(help_text='License', on_delete=django.db.models.deletion.PROTECT, related_name='source_license', to='base.license'),
),
]
20 changes: 20 additions & 0 deletions src/datasources/migrations/0007_alter_datasource_source_license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.10 on 2024-06-07 12:47

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('base', '0004_license'),
('datasources', '0006_alter_datasource_source_license'),
]

operations = [
migrations.AlterField(
model_name='datasource',
name='source_license',
field=models.ForeignKey(help_text='License', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='data_sources', to='base.license'),
),
]
14 changes: 12 additions & 2 deletions src/datasources/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ class SourceSubdivision(TimeStampedModel):
max_length=128,
unique=True
)
external_name: models.CharField = models.CharField(
help_text=_('External Name'),
max_length=128,
null=True,
)
description: models.TextField = models.TextField(
help_text=_('Source description'),
max_length=1000,
Expand Down Expand Up @@ -73,10 +78,15 @@ class DataSource(TimeStampedModel):
null=True,
blank=True
)
source_license: models.CharField = models.CharField(

source_license: models.ForeignKey = models.ForeignKey(
'base.License',
related_name='data_sources',
help_text=_('License'),
max_length=128
on_delete=models.PROTECT,
null=True
)

links: models.ManyToManyField = models.ManyToManyField(
'base.Link',
help_text=_('DataSource links'),
Expand Down
17 changes: 14 additions & 3 deletions src/datasources/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
from import_export import resources
from import_export.fields import Field, widgets

from base.models import Link, LinkTypeChoices
from base.models import Link, LinkTypeChoices, License
from datasources.models import DataSource, SourceSubdivision


class SourceSubdivisionResource(resources.ModelResource):
name = Field(attribute='name', column_name='Source Subdivision')
display_name = Field(attribute='display_name', column_name='Source Subdivision')
external_name = Field(attribute='external_name', column_name='External Name')
description = Field(attribute='description', column_name='Description')
db_source = Field(attribute='db_source', column_name='DB Source')
data_source = Field(
Expand All @@ -28,8 +29,8 @@ class SourceSubdivisionResource(resources.ModelResource):
class Meta:
model = SourceSubdivision
fields: tuple[Literal['name'], Literal['display_name'], Literal['description'],
Literal['data_source'], Literal['reference_signal'], Literal['links']]
fields = ('name', 'display_name', 'description', 'data_source', 'reference_signal', 'links')
Literal['data_source'], Literal['reference_signal'], Literal['links'], Literal['external_name']]
fields = ('name', 'display_name', 'description', 'data_source', 'reference_signal', 'links', 'external_name')
import_id_fields: list[str] = ['name']
skip_unchanged = True

Expand All @@ -39,6 +40,7 @@ def before_import_row(self, row, **kwargs) -> None:
any additional links specified in 'DUA' or 'Link' columns.
"""
self.process_links(row)
self.process_licenses(row)
self.process_datasource(row)

def process_links(self, row) -> None:
Expand All @@ -57,6 +59,13 @@ def process_links(self, row) -> None:
link, created = Link.objects.get_or_create(url=link_url, link_type=link_type)
row['Links'] += row['Links'] + f'|{link.url}'

def process_licenses(self, row) -> None:
if row['License']:
license: License
created: bool
license, created = License.objects.get_or_create(name=row['License'])
row['License'] = license

def process_datasource(self, row) -> None:
if row['Name']:
data_source: DataSource
Expand All @@ -70,4 +79,6 @@ def process_datasource(self, row) -> None:
}
)
links: QuerySet[Link] = Link.objects.filter(url__in=row['Links'].split('|')).values_list('id', flat=True)
license: License = License.objects.filter(name=row['License']).first()
data_source.links.add(*links)
data_source.source_license = license
14 changes: 14 additions & 0 deletions src/fixtures/available_geography.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"pk": 1,
"fields": {
"name": "county",
"display_name": "ADM2 (e.g. U.S. counties)",
"order_id": 3,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand All @@ -13,6 +15,8 @@
"pk": 2,
"fields": {
"name": "hhs",
"display_name": "HHS Regions",
"order_id": 4,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand All @@ -22,6 +26,8 @@
"pk": 3,
"fields": {
"name": "hrr",
"display_name": "Hospital Referral Regions (HRRs)",
"order_id": 6,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand All @@ -31,6 +37,8 @@
"pk": 4,
"fields": {
"name": "msa",
"display_name": "Metropolitan Statistical Areas (MSAs)",
"order_id": 5,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand All @@ -40,6 +48,8 @@
"pk": 5,
"fields": {
"name": "nation",
"display_name": "National",
"order_id": 1,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand All @@ -49,6 +59,8 @@
"pk": 6,
"fields": {
"name": "state",
"display_name": "ADM1 (e.g. U.S. states)",
"order_id": 2,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand All @@ -58,6 +70,8 @@
"pk": 7,
"fields": {
"name": "dma",
"display_name": "Designated Market Areas (DMAs)",
"order_id": 7,
"created": "2023-08-09T19:23:22.597131",
"modified": "2023-08-09T19:23:22.597131"
}
Expand Down
Loading
Loading