Skip to content
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

Eco updates from review #1056

Merged
merged 8 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion hawc/apps/eco/autocomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,20 @@ class EcoregionAutocomplete(BaseAutocomplete):
search_fields = ["value"]

def get_queryset(self):
return super().get_queryset().filter(category=constants.VocabCategories.ECOREGION)
return (
super()
.get_queryset()
.filter(category=constants.VocabCategories.ECOREGION, deprecated_on__isnull=True)
)


@register
class NestedTermAutocomplete(BaseAutocomplete):
model = models.NestedTerm
search_fields = ("id", "name")

def get_queryset(self):
return super().get_queryset().filter(deprecated_on__isnull=True)

def get_result_label(self, obj):
return f"{obj.label()} ({obj.id})"
4 changes: 4 additions & 0 deletions hawc/apps/eco/filterset.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class Meta:
}
main_field = "name__contains"

def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
return queryset.filter(deprecated_on__isnull=True)

@property
def has_query(self) -> bool:
return self.data.get("name__contains", "") != ""
Expand Down
1 change: 1 addition & 0 deletions hawc/apps/eco/fixtures/nestedterms_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"parents": ["Air", "Physical"], "fields": {"name": "acid rain", "type": "CE"}}, {"parents": ["Air", "Physical", "climate"], "fields": {"name": "storms/hurricanes", "type": "CE"}}, {"parents": ["Air", "Physical"], "fields": {"name": "excess energy", "type": "CE"}}, {"parents": ["Air", "Physical", "excess energy"], "fields": {"name": "light pollution", "type": "CE"}}, {"parents": ["Air", "Physical", "excess energy"], "fields": {"name": "noise pollution", "type": "CE"}}, {"parents": ["Air", "Physical", "excess energy"], "fields": {"name": "thermal pollution", "type": "CE"}}, {"parents": ["Air", "Physical"], "fields": {"name": "transportation and service corridors- flight paths", "type": "CE"}}, {"parents": ["Land", "Biological", "Birds"], "fields": {"name": "behavior", "type": "CE"}}, {"parents": ["Land", "Biological", "Birds"], "fields": {"name": "physiology/condition", "type": "CE"}}, {"parents": ["Land", "Biological", "Birds"], "fields": {"name": "reproduction/fecundity", "type": "CE"}}, {"parents": ["Land", "Biological"], "fields": {"name": "Resource use", "type": "CE"}}, {"parents": ["Land", "Biological", "Resource use"], "fields": {"name": "Hunting and collecting terrestrial animals", "type": "CE"}}, {"parents": ["Land", "Biological", "Resource use"], "fields": {"name": "Gathering terrestrial plants", "type": "CE"}}, {"parents": ["Land", "Biological", "Resource use"], "fields": {"name": "Logging and wood harvesting", "type": "CE"}}, {"parents": ["Land", "Biological"], "fields": {"name": "Terrestrial invasive species", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover"], "fields": {"name": "residential/commercial development", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "residential/commercial development"], "fields": {"name": "housing and urban areas", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "residential/commercial development"], "fields": {"name": "commercial and industrial areas", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "residential/commercial development"], "fields": {"name": "tourism and recreational areas", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "agriculture"], "fields": {"name": "annual and perennial non-timber crops", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "agriculture"], "fields": {"name": "wood and pulp plantations", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "agriculture"], "fields": {"name": "livestock farming and ranching", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover"], "fields": {"name": "energy production and mining", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "energy production and mining"], "fields": {"name": "oil and gas drilling", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "energy production and mining"], "fields": {"name": "mining and quarrying", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "energy production and mining"], "fields": {"name": "renewable energy", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover"], "fields": {"name": "transportation and service corridors", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "transportation and service corridors"], "fields": {"name": "roads and railroads", "type": "CE"}}, {"parents": ["Land", "Physical", "Land use/land cover", "transportation and service corridors"], "fields": {"name": "utility and service lines", "type": "CE"}}, {"parents": ["Land", "Physical"], "fields": {"name": "Geological events", "type": "CE"}}, {"parents": ["Land", "Physical", "Geological events"], "fields": {"name": "Volcanoes", "type": "CE"}}, {"parents": ["Land", "Physical", "Geological events"], "fields": {"name": "Earthquakes/tsunamis", "type": "CE"}}, {"parents": ["Land", "Physical", "Geological events"], "fields": {"name": "Avalanches/landslides", "type": "CE"}}, {"parents": ["Water", "Biological"], "fields": {"name": "Corals", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "abundance", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "biochemical", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals", "biochemical"], "fields": {"name": "enzyme", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals", "biochemical"], "fields": {"name": "stoichiometry", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "community structure", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals", "community structure"], "fields": {"name": "diversity", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals", "community structure"], "fields": {"name": "multimetric index", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals", "community structure"], "fields": {"name": "richness", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "genetic", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "growth/size/biomass", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "mortality", "type": "CE"}}, {"parents": ["Water", "Biological", "Corals"], "fields": {"name": "population structure", "type": "CE"}}, {"parents": ["Water", "Biological"], "fields": {"name": "Resource use", "type": "CE"}}, {"parents": ["Water", "Biological", "Resource use"], "fields": {"name": "Fishing and harvesting aquatic resources", "type": "CE"}}, {"parents": ["Water", "Physical", "Effluent"], "fields": {"name": "agricultural and forestry", "type": "CE"}}, {"parents": ["Water", "Physical", "Effluent"], "fields": {"name": "domestic and urban wastewater", "type": "CE"}}, {"parents": ["Water", "Physical", "Effluent"], "fields": {"name": "garbage and solid waste", "type": "CE"}}, {"parents": ["Water", "Physical", "Effluent"], "fields": {"name": "industrial and military", "type": "CE"}}, {"parents": ["Water", "Physical", "Hydrology"], "fields": {"name": "sea level rise", "type": "CE"}}, {"parents": ["Water", "Physical"], "fields": {"name": "Transportation and service corridors- shipping lanes", "type": "CE"}}]
File renamed without changes.
34 changes: 34 additions & 0 deletions hawc/apps/eco/fixtures/vocab_2.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{"pk": 203, "model": "eco.Vocab", "fields": {"category": 2, "value": "Freshwater aquatic"}}
{"pk": 204, "model": "eco.Vocab", "fields": {"category": 2, "parent": 203, "value": "Rivers and streams biome"}}
{"pk": 205, "model": "eco.Vocab", "fields": {"category": 2, "parent": 203, "value": "Artificial wetlands biome"}}
{"pk": 206, "model": "eco.Vocab", "fields": {"category": 2, "parent": 203, "value": "Lakes biome"}}
{"pk": 207, "model": "eco.Vocab", "fields": {"category": 2, "value": "Freshwater aquatic/Marine"}}
{"pk": 208, "model": "eco.Vocab", "fields": {"category": 2, "value": "Marine"}}
{"pk": 209, "model": "eco.Vocab", "fields": {"category": 2, "parent": 208, "value": "Marine shelf biome"}}
{"pk": 210, "model": "eco.Vocab", "fields": {"category": 2, "parent": 208, "value": "Pelagic ocean waters biome"}}
{"pk": 211, "model": "eco.Vocab", "fields": {"category": 2, "parent": 208, "value": "Deep sea floors biome"}}
{"pk": 212, "model": "eco.Vocab", "fields": {"category": 2, "parent": 208, "value": "Anthropogenic marine biome"}}
{"pk": 213, "model": "eco.Vocab", "fields": {"category": 2, "value": "Marine/Terrestrial"}}
{"pk": 214, "model": "eco.Vocab", "fields": {"category": 2, "parent": 213, "value": "Shorelines biome"}}
{"pk": 215, "model": "eco.Vocab", "fields": {"category": 2, "parent": 213, "value": "Supralittoral coastal biome"}}
{"pk": 216, "model": "eco.Vocab", "fields": {"category": 2, "parent": 213, "value": "Anthropogenic shorelines biome"}}
{"pk": 217, "model": "eco.Vocab", "fields": {"category": 2, "value": "Marine/Freshwater/Terrestrial"}}
{"pk": 218, "model": "eco.Vocab", "fields": {"category": 2, "parent": 217, "value": "Brackish tidal biome"}}
{"pk": 219, "model": "eco.Vocab", "fields": {"category": 2, "value": "Terrestrial"}}
{"pk": 220, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Tropical-subtropical forests biome"}}
{"pk": 221, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Temperate-boreal forests and woodlands biome"}}
{"pk": 222, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Shurblands and shrubby woodlands biome"}}
{"pk": 223, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Savannas and grasslands biome"}}
{"pk": 224, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Deserts and semi-deserts biome"}}
{"pk": 225, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Polar/alpine (cryogenic) biome"}}
{"pk": 226, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Intensive land-use biome (crops)"}}
{"pk": 227, "model": "eco.Vocab", "fields": {"category": 2, "parent": 219, "value": "Intensive land-use biome (urban)"}}
{"pk": 228, "model": "eco.Vocab", "fields": {"category": 2, "value": "Terrestrial/Freshwater"}}
{"pk": 229, "model": "eco.Vocab", "fields": {"category": 2, "parent": 228, "value": "Palustrine wetlands biome"}}
{"pk": 230, "model": "eco.Vocab", "fields": {"category": 2, "value": "Subterranean"}}
{"pk": 231, "model": "eco.Vocab", "fields": {"category": 2, "parent": 230, "value": "Lithic biome"}}
{"pk": 232, "model": "eco.Vocab", "fields": {"category": 2, "parent": 230, "value": "Anthropogenic voids biome"}}
{"pk": 233, "model": "eco.Vocab", "fields": {"category": 2, "value": "Subterranean/Freshwater"}}
{"pk": 234, "model": "eco.Vocab", "fields": {"category": 2, "parent": 233, "value": "Anthropogenic"}}
{"pk": 235, "model": "eco.Vocab", "fields": {"category": 2, "value": "Subterranean/Marine"}}
{"pk": 236, "model": "eco.Vocab", "fields": {"category": 2, "parent": 235, "value": "Tidal biome"}}
4 changes: 2 additions & 2 deletions hawc/apps/eco/migrations/0002_load_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ def load_fixture(apps, schema_editor):
here = Path(__file__).parent
fixtures = (here / "../fixtures").resolve()
call_command("loaddata", str(fixtures / "states.json"), app_label="eco")
call_command("loaddata", str(fixtures / "vocab.json"), app_label="eco")
call_command("loaddata", str(fixtures / "nestedterms.jsonl"), app_label="eco")
call_command("loaddata", str(fixtures / "vocab_1.json"), app_label="eco")
call_command("loaddata", str(fixtures / "nestedterms_1.jsonl"), app_label="eco")


def unload_fixture(apps, schema_editor):
Expand Down
129 changes: 129 additions & 0 deletions hawc/apps/eco/migrations/0006_update_vocab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import json
from pathlib import Path

import django.db.models.deletion
from django.core.management import call_command
from django.db import migrations, models
from django.utils import timezone

here = Path(__file__).parent
fixtures = (here / "../fixtures").resolve()


def load_vocab(apps, schema_editor):
now = timezone.now()

# deprecate existing
vocab = apps.get_model("eco", "Vocab")
vocab.objects.filter(category=2).exclude(id__in=[197, 198]).update(deprecated_on=now)

# load new values
call_command("loaddata", str(fixtures / "vocab_2.jsonl"), app_label="eco")


def load_nested_terms(apps, schema_editor):
now = timezone.now()

# load the "real model" since we to use Treebeard manager methods
from hawc.apps.eco.models import NestedTerm

# rename
NestedTerm.objects.filter(id=457).update(name="fire and fire suppression")
NestedTerm.objects.filter(id=60).update(name="Water withdrawal/abstraction")

# fmt: off
# mark as deprecated
NestedTerm.objects.filter(
id__in=[
37, 38, 39, 434, 435, 436, 437, 438, 439, 440, 456, 461, 468, 537, 538, 539, 593, 595
]
).update(deprecated_on=now)
# fmt: on

# load new terms. We can't use a django fixture because Treebeard reorders nodes and
# may change the `path` of nodes based on name (for this model)
additions = json.loads((fixtures / "nestedterms_2.json").read_text())
for addition in additions:
for i, parent_name in enumerate(addition["parents"]):
if i == 0:
parent = NestedTerm.objects.get(depth=1, name=parent_name)
else:
for child in parent.get_children():
if child.name == parent_name:
parent = child
break
parent.add_child(**addition["fields"])


class Migration(migrations.Migration):
dependencies = [
("eco", "0005_remove_restraints"),
]

operations = [
migrations.AddField(
model_name="nestedterm",
name="deprecated_on",
field=models.DateTimeField(blank=True, default=None, null=True),
),
migrations.AddField(
model_name="vocab",
name="deprecated_on",
field=models.DateTimeField(blank=True, default=None, null=True),
),
migrations.AlterField(
model_name="design",
name="climates",
field=models.ManyToManyField(
help_text='Select one or more <a rel="noopener noreferrer" target="_blank" href="http://koeppen-geiger.vu-wien.ac.at/present.htm">Koppen climate classifications</a> to which the evidence applies',
limit_choices_to={"category": 11, "deprecated_on": None},
related_name="designs_by_climate",
to="eco.vocab",
),
),
migrations.AlterField(
model_name="design",
name="design",
field=models.ForeignKey(
help_text="Select study design",
limit_choices_to={"category": 0, "deprecated_on": None},
on_delete=django.db.models.deletion.CASCADE,
related_name="designs_by_type",
to="eco.vocab",
),
),
migrations.AlterField(
model_name="design",
name="ecoregions",
field=models.ManyToManyField(
blank=True,
help_text='Select one or more <a rel="noopener noreferrer" target="_blank" href="https://www.epa.gov/eco-research/level-iii-and-iv-ecoregions-continental-united-states">Level III Ecoregions</a> from the continental US, if known',
limit_choices_to={"category": 12, "deprecated_on": None},
related_name="designs_by_ecoregion",
to="eco.vocab",
),
),
migrations.AlterField(
model_name="design",
name="habitats",
field=models.ManyToManyField(
help_text='Select one or more <a rel="noopener noreferrer" target="_blank" href="https://global-ecosystems.org/">IUCN Global Ecosystems</a> to which the evidence applies.',
limit_choices_to={"category": 2, "deprecated_on": None},
related_name="designs_by_habitat",
to="eco.vocab",
),
),
migrations.AlterField(
model_name="design",
name="study_setting",
field=models.ForeignKey(
help_text="Select the setting in which evidence was generated",
limit_choices_to={"category": 1, "deprecated_on": None},
on_delete=django.db.models.deletion.CASCADE,
related_name="designs_by_setting",
to="eco.vocab",
),
),
migrations.RunPython(load_vocab, reverse_code=migrations.RunPython.noop),
migrations.RunPython(load_nested_terms, reverse_code=migrations.RunPython.noop),
]
16 changes: 9 additions & 7 deletions hawc/apps/eco/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class NestedTerm(MP_Node):
created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
notes = models.TextField(blank=True)
deprecated_on = models.DateTimeField(blank=True, default=None, null=True)

node_order_by = ["name"]

Expand Down Expand Up @@ -76,6 +77,7 @@ class Vocab(models.Model):
related_name="children",
related_query_name="children",
)
deprecated_on = models.DateTimeField(blank=True, default=None, null=True)

class Meta:
verbose_name = "Controlled vocabulary"
Expand All @@ -95,14 +97,14 @@ class Design(models.Model):
name = models.CharField(max_length=128, help_text="Name to refer to this study design")
design = models.ForeignKey(
Vocab,
limit_choices_to={"category": VocabCategories.TYPE},
limit_choices_to={"category": VocabCategories.TYPE, "deprecated_on": None},
on_delete=models.CASCADE,
help_text="Select study design",
related_name="designs_by_type",
)
study_setting = models.ForeignKey(
Vocab,
limit_choices_to={"category": VocabCategories.SETTING},
limit_choices_to={"category": VocabCategories.SETTING, "deprecated_on": None},
on_delete=models.CASCADE,
help_text="Select the setting in which evidence was generated",
related_name="designs_by_setting",
Expand All @@ -118,14 +120,14 @@ class Design(models.Model):
ecoregions = models.ManyToManyField(
Vocab,
blank=True,
limit_choices_to={"category": VocabCategories.ECOREGION},
help_text=f"Select one or more {new_window_a('https://www.epa.gov/eco-research/level-iii-and-iv-ecoregions-continental-united-states', 'Level III Ecoregions')}, if known",
limit_choices_to={"category": VocabCategories.ECOREGION, "deprecated_on": None},
help_text=f"Select one or more {new_window_a('https://www.epa.gov/eco-research/level-iii-and-iv-ecoregions-continental-united-states', 'Level III Ecoregions')} from the continental US, if known", # noqa: S608
related_name="designs_by_ecoregion",
)
habitats = models.ManyToManyField(
Vocab,
limit_choices_to={"category": VocabCategories.HABITAT},
help_text="Select one or more habitats to which the evidence applies.",
limit_choices_to={"category": VocabCategories.HABITAT, "deprecated_on": None},
help_text=f"Select one or more {new_window_a('https://global-ecosystems.org/', 'IUCN Global Ecosystems')} to which the evidence applies.",
related_name="designs_by_habitat",
)
habitats_as_reported = models.TextField(
Expand All @@ -135,7 +137,7 @@ class Design(models.Model):
)
climates = models.ManyToManyField(
Vocab,
limit_choices_to={"category": VocabCategories.CLIMATE},
limit_choices_to={"category": VocabCategories.CLIMATE, "deprecated_on": None},
help_text=f"Select one or more {new_window_a('http://koeppen-geiger.vu-wien.ac.at/present.htm', 'Koppen climate classifications')} to which the evidence applies",
related_name="designs_by_climate",
)
Expand Down
Loading