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
20 changes: 17 additions & 3 deletions apps/baseline/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
FoodPurchase,
Hazard,
Hunting,
KeyParameter,
LivelihoodActivity,
LivelihoodStrategy,
LivelihoodZone,
Expand Down Expand Up @@ -204,7 +205,6 @@ def bss_uploaded_date_time(self, instance):
return ""

def get_fieldsets(self, request, obj=None):

fieldsets = super().get_fieldsets(request, obj=obj)
if obj and obj.geography:
# Check if 'geography' field has a value
Expand Down Expand Up @@ -1013,7 +1013,6 @@ class EventAdmin(admin.ModelAdmin):


class ExpandabilityFactorAdmin(admin.ModelAdmin):

fields = (
"livelihood_strategy",
"wealth_group",
Expand Down Expand Up @@ -1046,7 +1045,6 @@ class ExpandabilityFactorAdmin(admin.ModelAdmin):


class CopingStrategyAdmin(admin.ModelAdmin):

fields = (
"community",
"leaders",
Expand Down Expand Up @@ -1075,6 +1073,20 @@ class CopingStrategyAdmin(admin.ModelAdmin):
)


class KeyParameterAdmin(admin.ModelAdmin):
list_display = (
"livelihood_zone_baseline",
"strategy_type",
"key_parameter_type",
"name",
"description",
)
search_fields = [
*translation_fields("name"),
*translation_fields("description"),
]


admin.site.register(SourceOrganization, SourceOrganizationAdmin)
admin.site.register(LivelihoodZone, LivelihoodZoneAdmin)
admin.site.register(LivelihoodZoneBaseline, LivelihoodZoneBaselineAdmin)
Expand All @@ -1098,3 +1110,5 @@ class CopingStrategyAdmin(admin.ModelAdmin):

admin.site.register(LivelihoodActivity, LivelihoodActivityAdmin)
admin.site.register(WealthGroupCharacteristicValue, WealthGroupCharacteristicValueAdmin)

admin.site.register(KeyParameter, KeyParameterAdmin)
127 changes: 127 additions & 0 deletions apps/baseline/migrations/0017_keyparameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields
from django.db import migrations, models

import common.fields


class Migration(migrations.Migration):
dependencies = [
("baseline", "0016_alter_livelihoodstrategy_additional_identifier_and_more"),
]

operations = [
migrations.CreateModel(
name="KeyParameter",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
(
"created",
model_utils.fields.AutoCreatedField(
default=django.utils.timezone.now, editable=False, verbose_name="created"
),
),
(
"modified",
model_utils.fields.AutoLastModifiedField(
default=django.utils.timezone.now, editable=False, verbose_name="modified"
),
),
(
"strategy_type",
models.CharField(
choices=[
("MilkProduction", "Milk Production"),
("ButterProduction", "Butter Production"),
("MeatProduction", "Meat Production"),
("LivestockSale", "Livestock Sale"),
("CropProduction", "Crop Production"),
("FoodPurchase", "Food Purchase"),
("PaymentInKind", "Payment in Kind"),
("ReliefGiftOther", "Relief, Gift or Other Food"),
("Hunting", "Hunting"),
("Fishing", "Fishing"),
("WildFoodGathering", "Wild Food Gathering"),
("OtherCashIncome", "Other Cash Income"),
("OtherPurchase", "Other Purchase"),
],
db_index=True,
help_text="The type of livelihood strategy, such as crop production, or wild food gathering.",
max_length=30,
verbose_name="Strategy Type",
),
),
(
"key_parameter_type",
models.CharField(
choices=[("price", "Price"), ("quantity", "Quantity")],
help_text="The type of key parameter, such as quantity or price.",
max_length=30,
verbose_name="Key Parameter Type",
),
),
("name_en", common.fields.NameField(max_length=200, verbose_name="Name")),
("name_fr", common.fields.NameField(blank=True, max_length=200, verbose_name="Name")),
("name_es", common.fields.NameField(blank=True, max_length=200, verbose_name="Name")),
("name_pt", common.fields.NameField(blank=True, max_length=200, verbose_name="Name")),
("name_ar", common.fields.NameField(blank=True, max_length=200, verbose_name="Name")),
(
"description_en",
common.fields.DescriptionField(
blank=True,
help_text="Any extra information or detail that is relevant to the object.",
max_length=2000,
verbose_name="Description",
),
),
(
"description_fr",
common.fields.DescriptionField(
blank=True,
help_text="Any extra information or detail that is relevant to the object.",
max_length=2000,
verbose_name="Description",
),
),
(
"description_es",
common.fields.DescriptionField(
blank=True,
help_text="Any extra information or detail that is relevant to the object.",
max_length=2000,
verbose_name="Description",
),
),
(
"description_pt",
common.fields.DescriptionField(
blank=True,
help_text="Any extra information or detail that is relevant to the object.",
max_length=2000,
verbose_name="Description",
),
),
(
"description_ar",
common.fields.DescriptionField(
blank=True,
help_text="Any extra information or detail that is relevant to the object.",
max_length=2000,
verbose_name="Description",
),
),
(
"livelihood_zone_baseline",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="baseline.livelihoodzonebaseline",
verbose_name="Livelihood Zone Baseline",
),
),
],
options={
"abstract": False,
},
),
]
45 changes: 45 additions & 0 deletions apps/baseline/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2360,3 +2360,48 @@ class Strategy(models.TextChoices):
class Meta:
verbose_name = _("Coping Strategy")
verbose_name_plural = _("Coping Strategies")


class KeyParameter(common_models.Model):
"""
These are 'key parameters' for a given BSS, as reported in the baseline Fact Sheets.

These are defined as:

> a source that contributes at least 10% of the kilocalories of one wealth group’s total food or income,
or at least 5% of two wealth groups' total food or income

These are entered manually for three reasons:
1. We expect to have to support manual overrides anyway.
2. We lack sufficient data (eg, product kcals per unit, strategy sub-type production figures) [1]
3. We haven't yet reverse-engineered the formulae in the LIAS for making kcals and cash comparable.

[1] A price on a purchase LS is presumably what the Fact Sheets call a 'consumer price'. A price on a
livestock sale is presumably always a 'producer price'. Labor figures are presumably the ones from the
livelihood activity detail. And animal numbers and school stats are presumably wealth group characteristics.
"""

class KeyParameterType(models.TextChoices):
PRICE = "price", _("Price")
QUANTITY = "quantity", _("Quantity")

livelihood_zone_baseline = models.ForeignKey(
LivelihoodZoneBaseline,
on_delete=models.CASCADE,
verbose_name=_("Livelihood Zone Baseline"),
)
strategy_type = models.CharField(
max_length=30,
choices=LivelihoodStrategyType.choices,
db_index=True,
verbose_name=_("Strategy Type"),
help_text=_("The type of livelihood strategy, such as crop production, or wild food gathering."),
)
key_parameter_type = models.CharField(
max_length=30,
choices=KeyParameterType.choices,
verbose_name=_("Key Parameter Type"),
help_text=_("The type of key parameter, such as quantity or price."),
)
name = TranslatedField(common_models.NameField(max_length=200))
description = TranslatedField(common_models.DescriptionField())
32 changes: 32 additions & 0 deletions apps/baseline/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
FoodPurchase,
Hazard,
Hunting,
KeyParameter,
LivelihoodActivity,
LivelihoodProductCategory,
LivelihoodStrategy,
Expand Down Expand Up @@ -1466,3 +1467,34 @@ def get_strategy_label(self, obj):

def get_wealth_group_label(self, obj):
return str(obj.wealth_group)


class KeyParameterSerializer(serializers.ModelSerializer):
class Meta:
model = KeyParameter
fields = [
"id",
"livelihood_zone_baseline",
"livelihood_zone_baseline_label",
"strategy_type",
"strategy_type_label",
"key_parameter_type",
"key_parameter_type_label",
"name",
"description",
]

strategy_type_label = serializers.SerializerMethodField()

def get_strategy_type_label(self, obj):
return obj.get_strategy_type_display()

key_parameter_type_label = serializers.SerializerMethodField()

def get_key_parameter_type_label(self, obj):
return obj.get_key_parameter_type_display()

livelihood_zone_baseline_label = serializers.SerializerMethodField()

def get_livelihood_zone_baseline_label(self, obj):
return str(obj.livelihood_zone_baseline)
42 changes: 42 additions & 0 deletions apps/baseline/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
FoodPurchase,
Hazard,
Hunting,
KeyParameter,
LivelihoodActivity,
LivelihoodProductCategory,
LivelihoodStrategy,
Expand Down Expand Up @@ -799,3 +800,44 @@ class Meta:
)
strategy = factory.Iterator(["reduce", "increase"])
by_value = fuzzy.FuzzyInteger(0, 100)


class KeyParameterFactory(factory.django.DjangoModelFactory):
class Meta:
model = KeyParameter
django_get_or_create = [
"livelihood_zone_baseline",
"strategy_type",
"key_parameter_type",
"name_en",
]

strategy_type = factory.Iterator(
[
"MilkProduction",
"ButterProduction",
"MeatProduction",
"LivestockSale",
"CropProduction",
"FoodPurchase",
"PaymentInKind",
"ReliefGiftOther",
"Fishing",
"Hunting",
"WildFoodGathering",
"OtherCashIncome",
"OtherPurchase",
]
)
livelihood_zone_baseline = factory.SubFactory(LivelihoodZoneBaselineFactory)
key_parameter_type = factory.Iterator(["quantity", "price"])
name_en = factory.Sequence(lambda n: f"Key parameter {n} en")
name_fr = factory.Sequence(lambda n: f"Key parameter {n} fr")
name_es = factory.Sequence(lambda n: f"Key parameter {n} es")
name_pt = factory.Sequence(lambda n: f"Key parameter {n} pt")
name_ar = factory.Sequence(lambda n: f"Key parameter {n} ar")
description_en = factory.LazyAttribute(lambda o: f"{o.name_en} description")
description_fr = factory.LazyAttribute(lambda o: f"{o.name_fr} description")
description_es = factory.LazyAttribute(lambda o: f"{o.name_es} description")
description_pt = factory.LazyAttribute(lambda o: f"{o.name_pt} description")
description_ar = factory.LazyAttribute(lambda o: f"{o.name_ar} description")
8 changes: 8 additions & 0 deletions apps/baseline/tests/test_factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
FoodPurchase,
Hazard,
Hunting,
KeyParameter,
LivelihoodActivity,
LivelihoodProductCategory,
LivelihoodStrategy,
Expand Down Expand Up @@ -55,6 +56,7 @@
FoodPurchaseFactory,
HazardFactory,
HuntingFactory,
KeyParameterFactory,
LivelihoodActivityFactory,
LivelihoodProductCategoryFactory,
LivelihoodStrategyFactory,
Expand Down Expand Up @@ -264,6 +266,11 @@ def test_copingstrategy_factory(self):
CopingStrategyFactory()
self.assertEqual(CopingStrategy.objects.count(), self.num_records)

def test_key_parameter_factory(self):
for _ in range(self.num_records):
KeyParameterFactory()
self.assertEqual(KeyParameter.objects.count(), self.num_records)

def test_all_factories(self):
for _ in range(2):
SourceOrganizationFactory()
Expand Down Expand Up @@ -302,3 +309,4 @@ def test_all_factories(self):
EventFactory()
ExpandabilityFactorFactory()
CopingStrategyFactory()
KeyParameterFactory()
Loading
Loading