Skip to content

Commit

Permalink
Merge pull request #20 from wmo-raf/dev
Browse files Browse the repository at this point in the history
Updates for custom data parameters
  • Loading branch information
erick-otenyo authored Apr 15, 2024
2 parents dc410e5 + 30e5141 commit acff0b8
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 40 deletions.
40 changes: 20 additions & 20 deletions forecastmanager/forecast_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
from wagtail.contrib.settings.registry import register_setting
from wagtail.models import Orderable

from forecastmanager.constants import WEATHER_PARAMETER_CHOICES, WEATHER_PARAMETERS_AS_DICT
from forecastmanager.widgets import WeatherSymbolChooserWidget
from forecastmanager.constants import WEATHER_PARAMETERS_AS_DICT
from forecastmanager.widgets import WeatherSymbolChooserWidget, DataParameterWidget


@register_setting
class ForecastSetting(ClusterableModel, BaseSiteSetting):
enable_auto_forecast = models.BooleanField(default=False, verbose_name=_('Enable automated forecasts'))
default_city = models.ForeignKey("City", blank=True, null=True, on_delete=models.CASCADE,
default_city = models.ForeignKey("City", blank=True, null=True, on_delete=models.SET_NULL,
verbose_name=_("Default City"))
weather_detail_page = models.ForeignKey("wagtailcore.Page", blank=True, null=True, on_delete=models.SET_NULL, )
weather_reports_page = models.ForeignKey("wagtailcore.Page", blank=True, null=True, on_delete=models.SET_NULL,
Expand Down Expand Up @@ -98,12 +98,11 @@ def save(self, *args, **kwargs):
class ForecastDataParameters(Orderable):
PARAMETER_TYPE_CHOICES = (
("numeric", _("Number")),
("time", _("Time")),
("text", _("Text")),
)
parent = ParentalKey(ForecastSetting, on_delete=models.CASCADE, related_name="data_parameters")
parameter = models.CharField(max_length=100, choices=WEATHER_PARAMETER_CHOICES, unique=True,
verbose_name=_("Parameter"))
use_known_parameters = models.BooleanField(default=True, verbose_name=_("Use predefined parameters"))
parameter = models.CharField(max_length=100, unique=True, verbose_name=_("Parameter"))
name = models.CharField(max_length=100, verbose_name=_("Parameter Label"),
help_text=_("Parameter name as locally labelled"))
parameter_type = models.CharField(max_length=100, choices=PARAMETER_TYPE_CHOICES, verbose_name=_("Parameter Type"),
Expand All @@ -112,31 +111,32 @@ class ForecastDataParameters(Orderable):
help_text="e.g °C, %, mm, hPa, etc ")

panels = [
FieldPanel('parameter'),
FieldPanel('use_known_parameters'),
FieldPanel('parameter', widget=DataParameterWidget),
FieldPanel('name'),
FieldPanel('parameter_type'),
FieldPanel('parameter_unit'),
]

def __str__(self):
return self.name

@property
def parameter_info(self):
return WEATHER_PARAMETERS_AS_DICT.get(self.parameter)
def units(self):
if self.parameter_unit:
return self.parameter_unit

def parse_value(self, value):
info = self.parameter_info
if self.parameter_info:
return self.parameter_info.get("units")

if not info.get("data_type"):
return value
return None

try:
if info.get("data_type") == "int":
return int(float(value))
elif info.get("data_type") == "float":
return float(value)
except ValueError:
pass
@property
def parameter_info(self):
return WEATHER_PARAMETERS_AS_DICT.get(self.parameter)

def parse_value(self, value):
# TODO: Implement parsing for different parameter types
return value


Expand Down
11 changes: 6 additions & 5 deletions forecastmanager/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,13 @@ def clean(self):

# check parameters
for param, value in params_data.items():
param = ForecastDataParameters.objects.filter(name=param).first()
if not param:
self.add_error(None, f"Unknown parameter found in table data: {param}")
return cleaned_data
if value:
param = ForecastDataParameters.objects.filter(name=param).first()
if not param:
self.add_error(None, f"Unknown parameter found in table data: {param}")
return cleaned_data

city_data["data_values"].append({"parameter": param, "value": value})
city_data["data_values"].append({"parameter": param, "value": value})

forecast_data.append(city_data)
added_cities.append(city.id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.3 on 2024-04-15 06:55

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


class Migration(migrations.Migration):

dependencies = [
('forecastmanager', '0021_forecastsetting_weather_reports_page'),
]

operations = [
migrations.AlterField(
model_name='forecastdataparameters',
name='parameter_type',
field=models.CharField(choices=[('numeric', 'Number'), ('text', 'Text')], default='numeric', max_length=100, verbose_name='Parameter Type'),
),
migrations.AlterField(
model_name='forecastsetting',
name='default_city',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='forecastmanager.city', verbose_name='Default City'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.3 on 2024-04-15 11:07

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('forecastmanager', '0022_alter_forecastdataparameters_parameter_type_and_more'),
]

operations = [
migrations.AddField(
model_name='forecastdataparameters',
name='use_known_parameters',
field=models.BooleanField(default=True, verbose_name='Use known parameters'),
),
]
25 changes: 19 additions & 6 deletions forecastmanager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Meta:
unique_together = ("forecast_date", "effective_period")
verbose_name = _("Forecast")
verbose_name_plural = _("Forecasts")
ordering = ["forecast_date", "effective_period"]
ordering = ["-forecast_date", "effective_period"]

panels = [
FieldPanel("forecast_date"),
Expand Down Expand Up @@ -126,15 +126,22 @@ def effective_period(self):
def data_values_dict(self):
data_values = {}
for data_value in self.data_values.all():
data_values[data_value.parameter.parameter] = {
parameter_info = data_value.parameter.parameter_info
val = {
"value": data_value.parsed_value,
"name": data_value.parameter.name,
"label": data_value.parameter.parameter_info.get("label"),
"units": data_value.parameter.parameter_info.get("unit"),
"label": data_value.parameter.name,
"units": data_value.parameter.units,
"value_with_units": data_value.value_with_units,
"icon": data_value.parameter.parameter_info.get("icon"),
}

if parameter_info:
val.update({
"icon": data_value.parameter.parameter_info.get("icon"),
})

data_values[data_value.parameter.parameter] = val

# Group temperature values
temperature = {}
if "air_temperature_max" in data_values:
Expand Down Expand Up @@ -201,4 +208,10 @@ def parsed_value(self):

@property
def value_with_units(self):
return f"{self.parsed_value}{self.parameter.parameter_info.get('unit')}"
if not self.parsed_value:
return None

if not self.parameter.units:
return self.parsed_value

return f"{self.parsed_value} {self.parameter.units}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
function DataParameterWidget(id, initialValue) {
const inputId = '#' + id
this.input = $(inputId);

const parameterListSelectId = id + "_parameter_list"
this.parameterListSelectInput = $("#" + parameterListSelectId);

const useKnownParameterInputId = id.split("-parameter")[0] + "-use_known_parameters"
this.checkIsKnownParameterInput = $("#" + useKnownParameterInputId)

const that = this

this.checkIsKnownParameterInput.change(function () {
const checked = $(this).is(":checked")

if (checked) {
that.input.hide()
that.parameterListSelectInput.show()
} else {
that.input.show()
that.parameterListSelectInput.hide()
}

})

if (this.checkIsKnownParameterInput.is(":checked")) {
// clear any previous value
that.parameterListSelectInput.show()
} else {
that.input.show()
}

this.parameterListSelectInput.change(function () {
const selectedVal = $(this).val()
that.setState(selectedVal)
})
}

DataParameterWidget.prototype.setState = function (newState) {
this.input.val(newState);
};

DataParameterWidget.prototype.getState = function () {
return this.input.val();
};

DataParameterWidget.prototype.getValue = function () {
return this.input.val();
};

DataParameterWidget.prototype.focus = function () {
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ <h2>Match Fields</h2>
},
...this.parameters.map((p) => ({
type: p.parameter_type,
allowEmpty: false,
allowEmpty: true,
allowInvalid: false,
})),
{
Expand Down
12 changes: 7 additions & 5 deletions forecastmanager/templates/forecastmanager/edit_forecast.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ <h2>{{ city_forecast.city.name }}</h2>
alt="">
</td>
{% for param in weather_parameters %}
{% for data in city_forecast.data_values.all %}
{% if data.parameter.parameter == param.parameter %}
<td>{{ data.value_with_units }}</td>
{% endif %}
{% endfor %}
<td>
{% for data in city_forecast.data_values.all %}
{% if data.parameter.parameter == param.parameter %}
{{ data.value_with_units }}
{% endif %}
{% endfor %}
</td>
{% endfor %}
</tr>
{% endfor %}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %}
value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}
style="display: none">

<select style="display: none" id="{{ widget.attrs.id }}_parameter_list">
<option value="">-----------</option>
{% for option in widget.parameter_list %}
<option value="{{ option.value }}"
{% if widget.value and widget.value == option.value %}selected{% endif %}>{{ option.label }}</option>
{% endfor %}
</select>
41 changes: 39 additions & 2 deletions forecastmanager/widgets.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import json

from django.forms import widgets
from django.forms import widgets, TextInput
from django.templatetags.static import static
from wagtail.telepath import register
from wagtail.utils.widgets import WidgetWithScript
from wagtail.widget_adapters import WidgetAdapter

from forecastmanager.constants import WEATHER_CONDITION_ICONS
from forecastmanager.constants import WEATHER_CONDITION_ICONS, WEATHER_PARAMETER_CHOICES


class WeatherSymbolChooserWidget(WidgetWithScript, widgets.TextInput):
Expand Down Expand Up @@ -52,3 +52,40 @@ class Media:


register(WeatherSymbolWidgetAdapter(), WeatherSymbolChooserWidget)


class DataParameterWidget(WidgetWithScript, TextInput):
template_name = "forecastmanager/forecast_data_parameter_widget.html"

def __init__(self, attrs=None, **kwargs):
default_attrs = {}

if attrs:
default_attrs.update(attrs)

super().__init__(default_attrs)

def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)

options = []

for choice in WEATHER_PARAMETER_CHOICES:
options.append({
"value": choice[0],
"label": choice[1],
})

context["widget"].update({
"parameter_list": options
})

return context

def render_js_init(self, id_, name, value):
return "new DataParameterWidget({0},{1});".format(json.dumps(id_), json.dumps(value))

class Media:
js = [
"forecastmanager/js/forecast-data-parameter-widget.js",
]
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = forecastmanager
version = 0.4.7
version = 0.4.8
description = Integration of Weather City Forecasts Manager in Wagtail Projects.
long_description = file:README.md
long_description_content_type = text/markdown
Expand Down

0 comments on commit acff0b8

Please sign in to comment.