Skip to content

Commit a456fb6

Browse files
authored
Merge pull request #225 from American-Institutes-for-Research/HEA-874/Change-the-characterstics_group-field-of-WealthCharacteristic-a-forgein-key
Hea 874/change the characterstics group field of wealth characteristic a forgein key
2 parents 0ab06cb + 4ff87cd commit a456fb6

8 files changed

Lines changed: 208 additions & 8 deletions

File tree

apps/baseline/serializers.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,11 @@ def get_characteristic_group(self, obj):
438438
"""
439439
if obj.product and obj.product.cpc.startswith("L02"):
440440
return "Livestock"
441-
return obj.wealth_characteristic.characteristic_group
441+
return (
442+
obj.wealth_characteristic.characteristic_group.code
443+
if obj.wealth_characteristic.characteristic_group
444+
else None
445+
)
442446

443447
product_common_name = serializers.CharField(source="product.common_name", read_only=True, allow_null=True)
444448
unit_of_measure_description = serializers.CharField(
@@ -542,7 +546,11 @@ def get_characteristic_group(self, obj):
542546
"""
543547
if obj.product and obj.product.cpc.startswith("L02"):
544548
return "Livestock"
545-
return obj.wealth_characteristic.characteristic_group
549+
return (
550+
obj.wealth_characteristic.characteristic_group.code
551+
if obj.wealth_characteristic.characteristic_group
552+
else None
553+
)
546554

547555
product_common_name = serializers.CharField(source="product.common_name", read_only=True, allow_null=True)
548556
unit_of_measure_description = serializers.CharField(

apps/baseline/tests/test_viewsets.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from common.tests.factories import ClassifiedProductFactory, CountryFactory
2424
from metadata.models import LivelihoodActivityScenario
2525
from metadata.tests.factories import (
26+
CharacteristicGroupFactory,
2627
LivelihoodCategoryFactory,
2728
WealthCharacteristicFactory,
2829
WealthGroupCategoryFactory,
@@ -1626,11 +1627,13 @@ def setUpTestData(cls):
16261627
wealth_group_category=cls.very_poor_wg,
16271628
community=cls.community,
16281629
)
1630+
# Create characteristic group
1631+
cls.population_group = CharacteristicGroupFactory(code="Population", name_en="Population")
16291632
# Create wealth characteristics
16301633
cls.char_with_group = WealthCharacteristicFactory(
16311634
code="household size",
16321635
name_en="Household size",
1633-
characteristic_group="Population",
1636+
characteristic_group=cls.population_group,
16341637
)
16351638
cls.char_without_group = WealthCharacteristicFactory(
16361639
code="other",

apps/metadata/admin.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from .models import (
88
ActivityLabel,
9+
CharacteristicGroup,
910
HazardCategory,
1011
LivelihoodCategory,
1112
Market,
@@ -85,6 +86,12 @@ class WealthGroupCategoryAdmin(ReferenceDataAdmin):
8586
"""
8687

8788

89+
class CharacteristicGroupAdmin(ReferenceDataAdmin):
90+
"""
91+
A concrete admin for CharacteristicGroup
92+
"""
93+
94+
8895
class WealthCharacteristicAdmin(ReferenceDataAdmin):
8996
"""
9097
A concrete admin for WealthCharacteristic
@@ -98,7 +105,7 @@ class WealthCharacteristicAdmin(ReferenceDataAdmin):
98105
*translation_fields("description"),
99106
"characteristic_group",
100107
)
101-
list_filter = ("variable_type",)
108+
list_filter = ("variable_type", "characteristic_group")
102109

103110

104111
class HazardCategoryAdmin(ReferenceDataAdmin):
@@ -226,6 +233,7 @@ class WealthCharacteristicLabelAdmin(admin.ModelAdmin):
226233

227234
admin.site.register(LivelihoodCategory, LivelihoodCategoryAdmin)
228235
admin.site.register(WealthGroupCategory, WealthGroupCategoryAdmin)
236+
admin.site.register(CharacteristicGroup, CharacteristicGroupAdmin)
229237
admin.site.register(SeasonalActivityType, SeasonalActivityTypeAdmin)
230238

231239
admin.site.register(Market, MarketAdmin)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Generated by Django 5.2.7 on 2026-01-26 06:44
2+
3+
import django.db.models.deletion
4+
import django.utils.timezone
5+
import model_utils.fields
6+
from django.db import migrations, models
7+
8+
import common.fields
9+
10+
11+
def forwards(apps, schema_editor):
12+
WealthCharacteristic = apps.get_model("metadata", "WealthCharacteristic")
13+
WealthCharacteristic.objects.update(characteristic_group=None)
14+
15+
16+
class Migration(migrations.Migration):
17+
18+
dependencies = [
19+
("metadata", "0013_wealthcharacteristic_characteristic_group"),
20+
]
21+
22+
operations = [
23+
migrations.RunPython(
24+
code=forwards,
25+
reverse_code=migrations.RunPython.noop,
26+
),
27+
migrations.CreateModel(
28+
name="CharacteristicGroup",
29+
fields=[
30+
(
31+
"created",
32+
model_utils.fields.AutoCreatedField(
33+
default=django.utils.timezone.now, editable=False, verbose_name="created"
34+
),
35+
),
36+
(
37+
"modified",
38+
model_utils.fields.AutoLastModifiedField(
39+
default=django.utils.timezone.now, editable=False, verbose_name="modified"
40+
),
41+
),
42+
(
43+
"code",
44+
common.fields.CodeField(max_length=60, primary_key=True, serialize=False, verbose_name="Code"),
45+
),
46+
(
47+
"ordering",
48+
models.PositiveSmallIntegerField(
49+
blank=True,
50+
help_text="The order to display the items in when sorting by this field, if not obvious.",
51+
null=True,
52+
verbose_name="Ordering",
53+
),
54+
),
55+
(
56+
"aliases",
57+
models.JSONField(
58+
blank=True,
59+
help_text="A list of alternate names for the object.",
60+
null=True,
61+
verbose_name="aliases",
62+
),
63+
),
64+
("name_en", common.fields.NameField(max_length=60, verbose_name="Name")),
65+
("name_fr", common.fields.NameField(blank=True, max_length=60, verbose_name="Name")),
66+
("name_es", common.fields.NameField(blank=True, max_length=60, verbose_name="Name")),
67+
("name_pt", common.fields.NameField(blank=True, max_length=60, verbose_name="Name")),
68+
("name_ar", common.fields.NameField(blank=True, max_length=60, verbose_name="Name")),
69+
(
70+
"description_en",
71+
common.fields.DescriptionField(
72+
blank=True,
73+
help_text="Any extra information or detail that is relevant to the object.",
74+
max_length=2000,
75+
verbose_name="Description",
76+
),
77+
),
78+
(
79+
"description_fr",
80+
common.fields.DescriptionField(
81+
blank=True,
82+
help_text="Any extra information or detail that is relevant to the object.",
83+
max_length=2000,
84+
verbose_name="Description",
85+
),
86+
),
87+
(
88+
"description_es",
89+
common.fields.DescriptionField(
90+
blank=True,
91+
help_text="Any extra information or detail that is relevant to the object.",
92+
max_length=2000,
93+
verbose_name="Description",
94+
),
95+
),
96+
(
97+
"description_pt",
98+
common.fields.DescriptionField(
99+
blank=True,
100+
help_text="Any extra information or detail that is relevant to the object.",
101+
max_length=2000,
102+
verbose_name="Description",
103+
),
104+
),
105+
(
106+
"description_ar",
107+
common.fields.DescriptionField(
108+
blank=True,
109+
help_text="Any extra information or detail that is relevant to the object.",
110+
max_length=2000,
111+
verbose_name="Description",
112+
),
113+
),
114+
],
115+
options={
116+
"verbose_name": "Characteristic Group",
117+
"verbose_name_plural": "Characteristic Groups",
118+
},
119+
),
120+
migrations.AlterField(
121+
model_name="wealthcharacteristic",
122+
name="characteristic_group",
123+
field=models.ForeignKey(
124+
blank=True,
125+
db_column="characteristic_group", # Add this line
126+
help_text="Optional grouping for characteristics, such as 'Population', 'Income', 'Land', 'Livestock', 'Other assets'",
127+
null=True,
128+
on_delete=django.db.models.deletion.PROTECT,
129+
to="metadata.characteristicgroup",
130+
verbose_name="Characteristic Group",
131+
),
132+
),
133+
]

apps/metadata/models.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ class Meta:
115115
verbose_name_plural = _("Livelihood Categories")
116116

117117

118+
class CharacteristicGroup(ReferenceData):
119+
"""
120+
A grouping for Wealth Characteristics, such as 'Population', 'Income', 'Land', 'Livestock', 'Other assets'.
121+
"""
122+
123+
objects = IdentifierManager.from_queryset(ReferenceDataQuerySet)()
124+
125+
class Meta:
126+
verbose_name = _("Characteristic Group")
127+
verbose_name_plural = _("Characteristic Groups")
128+
129+
118130
class WealthCharacteristic(ReferenceData):
119131
"""
120132
A Characteristic of a Wealth Group, such as `Number of children at school`, etc.
@@ -154,14 +166,16 @@ class VariableType(models.TextChoices):
154166
default=VariableType.STR,
155167
help_text=_("Whether the field is numeric, character, boolean, etc."),
156168
)
157-
characteristic_group = models.CharField(
158-
max_length=20,
169+
characteristic_group = models.ForeignKey(
170+
CharacteristicGroup,
171+
db_column="characteristic_group",
159172
blank=True,
160173
null=True,
174+
on_delete=models.PROTECT,
161175
verbose_name=_("Characteristic Group"),
162176
help_text=_(
163177
"Optional grouping for characteristics, such as 'Population', 'Income', "
164-
"'Land', 'Livestock', 'Poultry', 'Other assets'"
178+
"'Land', 'Livestock', 'Other assets'"
165179
),
166180
)
167181
objects = IdentifierManager.from_queryset(ReferenceDataQuerySet)()

apps/metadata/tests/factories.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import factory
22

33
from common.tests.factories import CountryFactory
4-
from metadata.models import Market, Season, SeasonalActivityType, WealthCharacteristic
4+
from metadata.models import (
5+
CharacteristicGroup,
6+
Market,
7+
Season,
8+
SeasonalActivityType,
9+
WealthCharacteristic,
10+
)
511

612

713
class LivelihoodCategoryFactory(factory.django.DjangoModelFactory):
@@ -58,6 +64,24 @@ class Meta:
5864
description_fr = factory.LazyAttribute(lambda o: f"{o.name_fr} Wealth Group Category Description fr")
5965

6066

67+
class CharacteristicGroupFactory(factory.django.DjangoModelFactory):
68+
class Meta:
69+
model = CharacteristicGroup
70+
django_get_or_create = ("code",)
71+
72+
code = factory.Iterator(["Population", "Income", "Land", "Livestock", "Other assets"])
73+
name_en = factory.LazyAttribute(lambda o: f"{o.code}")
74+
name_pt = factory.LazyAttribute(lambda o: f"{o.code} pt")
75+
name_es = factory.LazyAttribute(lambda o: f"{o.code} es")
76+
name_fr = factory.LazyAttribute(lambda o: f"{o.code} fr")
77+
name_ar = factory.LazyAttribute(lambda o: f"{o.code} ar")
78+
description_en = factory.LazyAttribute(lambda o: f"{o.code} Description en")
79+
description_pt = factory.LazyAttribute(lambda o: f"{o.code} Description pt")
80+
description_es = factory.LazyAttribute(lambda o: f"{o.code} Description es")
81+
description_ar = factory.LazyAttribute(lambda o: f"{o.code} Description ar")
82+
description_fr = factory.LazyAttribute(lambda o: f"{o.code} Description fr")
83+
84+
6185
class WealthCharacteristicFactory(factory.django.DjangoModelFactory):
6286
class Meta:
6387
model = "metadata.WealthCharacteristic"
@@ -73,6 +97,7 @@ class Meta:
7397
)
7498
has_product = factory.Iterator([False, True])
7599
has_unit_of_measure = factory.Iterator([False, True])
100+
characteristic_group = factory.SubFactory(CharacteristicGroupFactory)
76101
name_en = factory.LazyAttribute(lambda o: f"{o.code} Wealth Characteristic en")
77102
name_pt = factory.LazyAttribute(lambda o: f"{o.code} Wealth Characteristic pt")
78103
name_es = factory.LazyAttribute(lambda o: f"{o.code} Wealth Characteristic es")

templates/admin/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,12 @@
331331
<a href="{% url 'admin:metadata_wealthgroupcategory_changelist' %}">{% translate 'Wealth Categories' %}</a>
332332
</div>
333333
</div>
334+
<div class="card">
335+
<div class="card-body">
336+
<a href="{% url 'admin:metadata_characteristicgroup_changelist' %}">{% translate 'Characteristics Groups' %}</a>
337+
</div>
338+
</div>
339+
334340
<div class="card">
335341
<div class="card-body">
336342
<a href="{% url 'admin:metadata_wealthcharacteristic_changelist' %}">{% translate 'Wealth Group Characteristics' %}</a>

templates/admin/nav_sidebar.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@
286286
<li><a class="link-dark rounded"
287287
href="{% url 'admin:metadata_wealthgroupcategory_changelist' %}">{% translate 'Wealth Categories' %}</a>
288288
</li>
289+
<li><a class="link-dark rounded"
290+
href="{% url 'admin:metadata_characteristicgroup_changelist' %}">{% translate 'Characteristics Groups' %}</a>
291+
</li>
289292
<li><a class="link-dark rounded"
290293
href="{% url 'admin:metadata_wealthcharacteristic_changelist' %}">{% translate 'Wealth Group Characteristics' %}</a>
291294
</li>

0 commit comments

Comments
 (0)