Skip to content

Commit 3916820

Browse files
authored
Merge pull request #9 from KWB-R/feature/many-to-many-references
add m2m field for QMRAReference in QMRATreatment
2 parents 38eac10 + 55c2a7f commit 3916820

12 files changed

Lines changed: 127 additions & 26 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ qmra-prod.db
99
dump*
1010
prod-migrations/
1111
*.tar
12-
.vscode
12+
.vscode
13+
test.zip

infra/helm/qmra/templates/deployment.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,6 @@ spec:
1919
{{- include "app.labels" . | nindent 8 }}
2020
spec:
2121
initContainers:
22-
- name: move-static
23-
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
24-
envFrom:
25-
- configMapRef:
26-
name: {{ .Values.configmap_name }}
27-
volumeMounts:
28-
- name: static
29-
mountPath: {{ .Values.static.mount_path }}
30-
command: [ python, manage.py, collectstatic, --noinput ]
3122
- name: migrate
3223
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
3324
envFrom:
@@ -46,6 +37,15 @@ spec:
4637
- name: qmra-default
4738
mountPath: {{ .Values.qmra_default.mount_path }}
4839
command: [ python, manage.py, migrate, --database, qmra ]
40+
- name: move-static
41+
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
42+
envFrom:
43+
- configMapRef:
44+
name: {{ .Values.configmap_name }}
45+
volumeMounts:
46+
- name: static
47+
mountPath: {{ .Values.static.mount_path }}
48+
command: [ python, manage.py, collectstatic, --noinput ]
4949
containers:
5050
- name: {{ .Chart.Name }}
5151
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

qmra/risk_assessment/admin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,14 @@ class QMRATreatmentAdmin(admin.ModelAdmin):
6464
("name", "group"),
6565
("bacteria_min", "bacteria_max"),
6666
"bacteria_reference",
67+
"bacteria_references",
6768
("viruses_min", "viruses_max"),
6869
"viruses_reference",
70+
"viruses_references",
6971
("protozoa_min", "protozoa_max"),
70-
"protozoa_reference"
72+
"protozoa_reference",
73+
"protozoa_references"
7174
]
75+
filter_horizontal = ["bacteria_references", "viruses_references", "protozoa_references"]
7276

7377
save_model = save_model

qmra/risk_assessment/dbrouter.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ def allow_migrate(self, db, app_label, model_name=None, **hints):
1717
"""
1818
if model_name is not None and "qmra" in model_name:
1919
return db == "qmra"
20-
return db == "default"
20+
# model_name is None when the migration is a RunPython or a RunSQL
21+
return db == "default" or model_name is None
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 5.0.6 on 2026-01-15 12:42
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('risk_assessment', '0006_qmrapathogen_qmrareference_qmrasource_qmraexposure_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='qmratreatment',
15+
name='bacteria_references',
16+
field=models.ManyToManyField(related_name='bacteria_lrvs', to='risk_assessment.qmrareference'),
17+
),
18+
migrations.AddField(
19+
model_name='qmratreatment',
20+
name='protozoa_references',
21+
field=models.ManyToManyField(related_name='protozoa_lrvs', to='risk_assessment.qmrareference'),
22+
),
23+
migrations.AddField(
24+
model_name='qmratreatment',
25+
name='viruses_references',
26+
field=models.ManyToManyField(related_name='viruses_lrvs', to='risk_assessment.qmrareference'),
27+
),
28+
]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 5.0.6 on 2026-01-15 12:42
2+
3+
from django.db import migrations
4+
5+
6+
def migrate_references(apps, schema_editor):
7+
if schema_editor.connection.alias != "qmra":
8+
return
9+
QMRATreatment = apps.get_model("risk_assessment", "QMRATreatment")
10+
for treatment in QMRATreatment.objects.all():
11+
12+
treatment.bacteria_references.add(treatment.bacteria_reference)
13+
treatment.viruses_references.add(treatment.viruses_reference)
14+
treatment.protozoa_references.add(treatment.protozoa_reference)
15+
16+
17+
class Migration(migrations.Migration):
18+
19+
dependencies = [
20+
('risk_assessment', '0007_qmratreatment_bacteria_references_and_more'),
21+
]
22+
23+
operations = [
24+
migrations.RunPython(migrate_references),
25+
]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 5.0.6 on 2026-01-15 12:42
2+
from django.core.management import call_command
3+
from django.db import migrations
4+
5+
6+
def migrate_references(apps, schema_editor):
7+
if schema_editor.connection.alias != "qmra":
8+
return
9+
QMRATreatment = apps.get_model("risk_assessment", "QMRATreatment")
10+
all_treatments = QMRATreatment.objects.all()
11+
if len(all_treatments) == 0:
12+
call_command("seed_default_db")
13+
all_treatments = QMRATreatment.objects.all()
14+
for treatment in all_treatments:
15+
16+
treatment.bacteria_references.add(treatment.bacteria_reference)
17+
treatment.viruses_references.add(treatment.viruses_reference)
18+
treatment.protozoa_references.add(treatment.protozoa_reference)
19+
treatment.save()
20+
call_command("export_default")
21+
22+
23+
class Migration(migrations.Migration):
24+
25+
dependencies = [
26+
('risk_assessment', '0008_auto_20260115_1342'),
27+
]
28+
29+
operations = [
30+
migrations.RunPython(migrate_references),
31+
]

qmra/risk_assessment/qmra_models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,19 @@ class QMRATreatment(models.Model):
270270
bacteria_max: Optional[float] = models.FloatField(blank=True, null=True)
271271
bacteria_reference = models.ForeignKey(QMRAReference, blank=True, null=True, on_delete=models.CASCADE,
272272
related_name="bacteria_lrv")
273+
bacteria_references = models.ManyToManyField(QMRAReference, related_name="bacteria_lrvs")
274+
273275
viruses_min: Optional[float] = models.FloatField(blank=True, null=True)
274276
viruses_max: Optional[float] = models.FloatField(blank=True, null=True)
275277
viruses_reference = models.ForeignKey(QMRAReference, blank=True, null=True, on_delete=models.CASCADE,
276278
related_name="viruses_lrv")
279+
viruses_references = models.ManyToManyField(QMRAReference, related_name="viruses_lrvs")
280+
277281
protozoa_min: Optional[float] = models.FloatField(blank=True, null=True)
278282
protozoa_max: Optional[float] = models.FloatField(blank=True, null=True)
279283
protozoa_reference = models.ForeignKey(QMRAReference, blank=True, null=True, on_delete=models.CASCADE,
280284
related_name="protozoa_lrv")
285+
protozoa_references = models.ManyToManyField(QMRAReference, related_name="protozoa_lrvs")
281286

282287
@classmethod
283288
def from_dict(cls, data):
@@ -288,6 +293,7 @@ def from_dict(cls, data):
288293
description=data['description'],
289294
bacteria_min=data['bacteria_min'],
290295
bacteria_max=data['bacteria_max'],
296+
# TODO: *_referenceS (m2m fields...)
291297
bacteria_reference_id=int(data["bacteria_reference"]) \
292298
if data["bacteria_reference"] is not None else None,
293299
viruses_min=data['viruses_min'],
@@ -303,8 +309,11 @@ def from_dict(cls, data):
303309
def to_dict(self):
304310
data = model_to_dict(self)
305311
data["bacteria_reference"] = str(self.bacteria_reference.pk) if self.bacteria_reference is not None else None
312+
data["bacteria_references"] = [str(ref.pk) for ref in self.bacteria_references.all()]
306313
data["viruses_reference"] = str(self.viruses_reference.pk) if self.viruses_reference is not None else None
314+
data["viruses_references"] = [str(ref.pk) for ref in self.viruses_references.all()]
307315
data["protozoa_reference"] = str(self.protozoa_reference.pk) if self.protozoa_reference is not None else None
316+
data["protozoa_references"] = [str(ref.pk) for ref in self.protozoa_references.all()]
308317
return data
309318

310319

qmra/risk_assessment/templates/treatments-form-js.html

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -388,22 +388,24 @@
388388
var inner = "";
389389
for (const treatment of this.treatments){
390390
if (!uniques.has(treatment.name)){
391-
const virus_ref = this.references[treatment.viruses_reference]
392-
const bacteria_ref = this.references[treatment.bacteria_reference]
393-
const protozoa_ref = this.references[treatment.protozoa_reference]
391+
const all_refs_id = new Set();
392+
for (const r of [...treatment.viruses_references, ...treatment.bacteria_references, ...treatment.protozoa_references]){
393+
all_refs_id.add(r);
394+
}
395+
const superscripts = [...all_refs_id].map((r, i) => { return `<sup>[${i+1}]</sup>` }).join('');
396+
const ref_footnotes = [...all_refs_id].map((r, i) => {
397+
const ref = this.references[r];
398+
return `<div class="small"><sup>[${i+1}]</sup>values taken from <a href="${ref.ReferenceLink}">${ref.ReferenceName}</a></div>`;
399+
}).join('');
394400
uniques.add(treatment.name)
395-
const ref = virus_ref === undefined ?
396-
bacteria_ref === undefined ? protozoa_ref === undefined ? "#" : protozoa_ref : bacteria_ref : virus_ref
397-
const link = ref.ReferenceLink;
398-
const name = ref.ReferenceName;
399401
inner += `<li>
400-
<h5>${treatment.name}</h5>
402+
<h5>${treatment.name}${superscripts}</h5>
401403
<div class="text-muted small mb-4">${treatment.description}</div>
402404
<table class="table small">
403405
<tr>
404406
<th>Pathogen group</th>
405-
<th>Minimum LRV<sup>[1]</sup></th>
406-
<th>Maximum LRV<sup>[1]</sup></th>
407+
<th>Minimum LRV</th>
408+
<th>Maximum LRV</th>
407409
</tr>
408410
<tr>
409411
<td>Viruses</td>
@@ -422,7 +424,7 @@ <h5>${treatment.name}</h5>
422424
</tr>
423425
424426
</table>
425-
<div class="small"><sup>[1]</sup>values taken from <a href="${link}">${name}</a></p>
427+
${ref_footnotes}
426428
</li>
427429
`
428430
}

qmra/risk_assessment/tests/test_assess_risk.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def test_with_all_pathogens(self):
7777
) for p, _ in QMRAPathogens.data.items()
7878
]
7979
given_treatments = [
80-
Treatment.from_default(QMRATreatments.get("Conventional clarification"), given_ra),
80+
Treatment.from_default(QMRATreatments.get("Coagulation, flocculation and media filtration"), given_ra),
8181
Treatment.from_default(QMRATreatments.get("Slow sand filtration"), given_ra),
8282
]
8383
given_ra.inflows.set(given_inflows, bulk=False)

0 commit comments

Comments
 (0)