Skip to content
Open
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
86 changes: 32 additions & 54 deletions data_models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,37 @@ def create_gcmd_str(categories):
return " > ".join(category for category in categories if category)


POSSIBLE_SEARCHABLE_FIELDS = [
'short_name',
'long_name',
'title',
'url',
'category',
'topic',
'term',
'variable_1',
'variable_2',
'variable_3',
'doi',
'concept_id',
'location',
'aliases__short_name',
'platform__short_name',
'platform__long_name',
]


class BaseModel(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False, unique=True)

@staticmethod
def search_fields():
return ["short_name", "long_name"]
def custom_search_fields(cls):
all_model_field_names = [field.name for field in cls._meta.get_fields()]
actual_searchable_names = [
field
for field in POSSIBLE_SEARCHABLE_FIELDS
if field.split('__')[0] in all_model_field_names
]
return actual_searchable_names

Comment on lines +67 to 75

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than supporting a list of each possible search field and checking against all fields of each subclass, could we not just override search_fields on the subclasses?

e.g.

class Image(BaseModel):
    ...
    @staticmethod
    def search_fields():
        return ["title"]

@classmethod
def search(cls, params):
Expand All @@ -56,7 +81,7 @@ def search(cls, params):
if search_fields_param:
search_fields = search_fields_param.split(",")
else:
search_fields = cls.search_fields()
search_fields = cls.custom_search_fields(cls)

queryset = cls.objects.all()

Expand All @@ -66,8 +91,9 @@ def search(cls, params):
queryset = queryset.annotate(search=vector).filter(
search=SearchQuery(search, search_type=search_type)
)

return queryset.filter(**params)
# TODO: adding this distinct massively slows down the application.
# How can we acheive the same result performantly?
return queryset.filter(**params) # .distinct('uuid')

def __str__(self):
return self.short_name
Expand All @@ -93,10 +119,6 @@ class Image(BaseModel):
owner = models.CharField(max_length=512, default="", blank=True)
source_url = models.TextField(blank=True, default="")

@staticmethod
def search_fields():
return ["title", "description"]

def __str__(self):
return self.title or self.image.name

Expand Down Expand Up @@ -172,10 +194,6 @@ class HomeBase(LimitedInfoPriority):
location = models.CharField(max_length=512, blank=True, default="")
additional_info = models.CharField(max_length=2048, blank=True, default="")

@staticmethod
def search_fields():
return ["short_name", "long_name", "location"]

class Meta(LimitedInfo.Meta):
pass

Expand Down Expand Up @@ -226,10 +244,6 @@ class Meta(LimitedInfo.Meta):
class WebsiteType(LimitedInfoPriority):
description = models.TextField(blank=True, default="")

@staticmethod
def search_fields():
return ["short_name", "long_name", "description"]

def __str__(self):
return self.long_name

Expand All @@ -256,10 +270,6 @@ class Alias(BaseModel):
# )
# return super(Alias, self).save(*args, **kwargs)

@staticmethod
def search_fields():
return ["short_name"]

class Meta:
verbose_name_plural = "Aliases"

Expand Down Expand Up @@ -377,10 +387,6 @@ class GcmdPhenomenon(GcmdKeyword):
gcmd_uuid = models.UUIDField(unique=True)
gcmd_path = ["category", "topic", "term", "variable_1", "variable_2", "variable_3"]

@staticmethod
def search_fields():
return ["category", "topic"]

def __str__(self):
categories = (
self.category,
Expand All @@ -406,10 +412,6 @@ class Website(BaseModel):
description = models.TextField(default="", blank=True)
notes_internal = models.TextField(default="", blank=True, help_text=NOTES_INTERNAL_HELP_TEXT)

@staticmethod
def search_fields():
return ["title", "description"]

def __str__(self):
return self.title

Expand Down Expand Up @@ -604,10 +606,6 @@ def instruments(self):
def platforms(self):
return select_related_distinct_data(self.deployments, "collection_periods__platform__uuid")

@staticmethod
def search_fields():
return ["short_name", "long_name", "description_short", "focus_phenomena"]

def get_absolute_url(self):
return urllib.parse.urljoin(FRONTEND_URL, f"/campaign/{self.uuid}/")

Expand Down Expand Up @@ -682,10 +680,6 @@ def campaigns(self):
def instruments(self):
return select_related_distinct_data(self.collection_periods, "instruments")

@staticmethod
def search_fields():
return ["short_name", "long_name", "description"]

def get_absolute_url(self):
return urllib.parse.urljoin(FRONTEND_URL, f"/platform/{self.uuid}/")

Expand Down Expand Up @@ -821,10 +815,6 @@ def platforms(self):
def get_absolute_url(self):
return urllib.parse.urljoin(FRONTEND_URL, f"/instrument/{self.uuid}/")

@staticmethod
def search_fields():
return ["short_name", "long_name", "description"]


class Deployment(DataModel):
campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE, related_name="deployments")
Expand Down Expand Up @@ -895,10 +885,6 @@ class IopSe(BaseModel):
help_text="Text filename of a specific granule file for reference",
)

@staticmethod
def search_fields():
return ["short_name", "description"]

class Meta:
abstract = True

Expand Down Expand Up @@ -1004,10 +990,6 @@ class CollectionPeriod(BaseModel):

auto_generated = models.BooleanField()

@staticmethod
def search_fields():
return ["campaign_deployment_base", "platform_owner"]

def __str__(self):
platform_id = f"({self.platform_identifier})" if self.platform_identifier else ""
campaign = str(self.deployment.campaign)
Expand Down Expand Up @@ -1042,9 +1024,5 @@ def __str__(self):
def get_absolute_url(self):
return urllib.parse.urljoin("https://doi.org", self.doi)

@staticmethod
def search_fields():
return ["concept_id", "long_name", "doi"]

class Meta:
verbose_name = "DOI"
103 changes: 103 additions & 0 deletions data_models/tests/custom_search_fields.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"PlatformType": [
"short_name",
"long_name"
],
"HomeBase": [
"short_name",
"long_name",
"location"
],
"Repository": [
"short_name",
"long_name"
],
"FocusArea": [
"short_name",
"long_name",
"url"
],
"Season": [
"short_name",
"long_name"
],
"MeasurementStyle": [
"short_name",
"long_name"
],
"MeasurementType": [
"short_name",
"long_name"
],
"MeasurementRegion": [
"short_name",
"long_name"
],
"GeographicalRegion": [
"short_name",
"long_name"
],
"GeophysicalConcept": [
"short_name",
"long_name"
],
"Campaign": [
"short_name",
"long_name",
"aliases__short_name"
],
"Platform": [
"short_name",
"long_name",
"aliases__short_name"
],
"Instrument": [
"short_name",
"long_name",
"aliases__short_name"
],
"Deployment": [
"short_name",
"long_name",
"aliases__short_name"
],
"IOP": [
"short_name"
],
"SignificantEvent": [
"short_name"
],
"PartnerOrg": [
"short_name",
"long_name",
"aliases__short_name"
],
"CollectionPeriod": [
"platform__short_name",
"platform__long_name"
],
"GcmdPhenomenon": [
"category",
"topic",
"term",
"variable_1",
"variable_2",
"variable_3"
],
"GcmdProject": [
"short_name",
"long_name"
],
"GcmdPlatform": [
"short_name",
"long_name",
"category"
],
"GcmdInstrument": [
"short_name",
"long_name"
],
"Alias": [
"short_name"
]
}
51 changes: 51 additions & 0 deletions data_models/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# to run this test file, use 'pytest -k data_models'

import pytest
from data_models import models
import json

model_names = [
"PlatformType",
"HomeBase",
"Repository",
"FocusArea",
"Season",
"MeasurementStyle",
"MeasurementType",
"MeasurementRegion",
"GeographicalRegion",
"GeophysicalConcept",
"Campaign",
"Platform",
"Instrument",
"Deployment",
"IOP",
"SignificantEvent",
"PartnerOrg",
"CollectionPeriod",
"GcmdPhenomenon",
"GcmdProject",
"GcmdPlatform",
"GcmdInstrument",
"Alias",
]


class TestStandAloneFunctions:
def test_create_gcmd_str(self):
categories = ['cat1', 'cat2', 'cat3', None, ""]

assert models.create_gcmd_str(categories) == 'cat1 > cat2 > cat3'


@pytest.mark.parametrize("model_name", model_names)
class TestModelFunctions:
def test_custom_search_fields(self, model_name):
"""Each model has a known list of fields or related fields that contain vaid names, such as short_name,
long_name, aliases, and various custom fields. The function being tested should output the correct list
for each model. We have a hard copy of the expected fields to test against.
"""
custom_search_fields = json.load(open('data_models/tests/custom_search_fields.json'))
model = getattr(models, model_name)

assert model.custom_search_fields(model) == custom_search_fields[model_name]