Skip to content

Commit 6595bbf

Browse files
committed
Separate model for history reference quantities
1 parent 2a192fd commit 6595bbf

4 files changed

Lines changed: 131 additions & 26 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Generated by Django 5.1.6 on 2025-04-16 18:52
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("data", "0030_quantity_derived_quantity"),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name="quantity",
15+
name="derived_quantity",
16+
),
17+
migrations.CreateModel(
18+
name="ReferenceQuantity",
19+
fields=[
20+
(
21+
"id",
22+
models.BigAutoField(
23+
auto_created=True,
24+
primary_key=True,
25+
serialize=False,
26+
verbose_name="ID",
27+
),
28+
),
29+
("value", models.JSONField()),
30+
("variance", models.JSONField()),
31+
("units", models.CharField(max_length=200)),
32+
("hash", models.IntegerField()),
33+
(
34+
"derived_quantity",
35+
models.ForeignKey(
36+
blank=True,
37+
null=True,
38+
on_delete=django.db.models.deletion.CASCADE,
39+
related_name="references",
40+
to="data.quantity",
41+
),
42+
),
43+
],
44+
),
45+
]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 5.1.6 on 2025-04-16 19:18
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("data", "0031_remove_quantity_derived_quantity_referencequantity"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="referencequantity",
15+
name="derived_quantity",
16+
field=models.ForeignKey(
17+
default=1,
18+
on_delete=django.db.models.deletion.CASCADE,
19+
related_name="references",
20+
to="data.quantity",
21+
),
22+
preserve_default=False,
23+
),
24+
]

sasdata/fair_database/data/models.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,24 @@ class Quantity(models.Model):
8484
DataSet, on_delete=models.CASCADE, related_name="data_contents"
8585
)
8686

87+
88+
class ReferenceQuantity(models.Model):
89+
# data value
90+
value = models.JSONField()
91+
92+
# variance of the data
93+
variance = models.JSONField()
94+
95+
# units
96+
units = models.CharField(max_length=200)
97+
98+
# hash value
99+
hash = models.IntegerField()
100+
87101
derived_quantity = models.ForeignKey(
88-
"self",
102+
Quantity,
89103
related_name="references",
90104
on_delete=models.CASCADE,
91-
blank=True,
92-
null=True,
93105
)
94106

95107

sasdata/fair_database/data/serializers.py

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,39 @@ def create(self, validated_data):
154154
return operation_tree
155155

156156

157+
class ReferenceQuantitySerializer(serializers.ModelSerializer):
158+
derived_quantity = serializers.PrimaryKeyRelatedField(
159+
queryset=models.Quantity, required=False
160+
)
161+
162+
class Meta:
163+
model = models.ReferenceQuantity
164+
fields = ["value", "variance", "units", "hash", "derived_quantity"]
165+
166+
def to_representation(self, instance):
167+
data = super().to_representation(instance)
168+
if "derived_quantity" in data:
169+
data.pop("derived_quantity")
170+
return data
171+
172+
def create(self, validated_data):
173+
derived_quantity = models.Quantity.objects.get(
174+
id=validated_data.pop("derived_quantity")
175+
)
176+
if "label" in validated_data:
177+
validated_data.pop("label")
178+
if "history" in validated_data:
179+
validated_data.pop("history")
180+
return models.ReferenceQuantity.objects.create(
181+
derived_quantity=derived_quantity, **validated_data
182+
)
183+
184+
157185
class QuantitySerializer(serializers.ModelSerializer):
158186
"""Serialization, deserialization, and validation for the Quantity model."""
159187

160188
operation_tree = OperationTreeSerializer(read_only=False, required=False)
161-
derived_quantity = serializers.PrimaryKeyRelatedField(
162-
queryset=models.Quantity, required=False, allow_null=True
163-
)
189+
references = ReferenceQuantitySerializer(many=True, read_only=False, required=False)
164190
label = serializers.CharField(max_length=20)
165191
dataset = serializers.PrimaryKeyRelatedField(
166192
queryset=models.DataSet, required=False, allow_null=True
@@ -178,14 +204,14 @@ class Meta:
178204
"references",
179205
"label",
180206
"dataset",
181-
"derived_quantity",
182207
"history",
183208
]
184209

185-
def validate_references(self, value):
186-
for ref in value:
187-
serializer = QuantitySerializer(data=ref)
188-
serializer.is_valid(raise_exception=True)
210+
def validate_history(self, value):
211+
if "references" in value:
212+
for ref in value["references"]:
213+
serializer = ReferenceQuantitySerializer(data=ref)
214+
serializer.is_valid(raise_exception=True)
189215

190216
# TODO: should variable-only history be assumed to refer to the same Quantity and ignored?
191217
# Extract operation tree from history
@@ -199,10 +225,11 @@ def to_internal_value(self, data):
199225
and not operations["operation"] == "variable"
200226
):
201227
data_copy["operation_tree"] = operations
202-
if "references" in data["history"]:
203-
data_copy["references"] = data["history"]["references"]
204-
data_copy.pop("history")
205-
return super().to_internal_value(data_copy)
228+
return_data = super().to_internal_value(data_copy)
229+
return_data["history"] = data["history"]
230+
return return_data
231+
else:
232+
return super().to_internal_value(data_copy)
206233
return super().to_internal_value(data)
207234

208235
# Serialize a Quantity instance
@@ -221,19 +248,14 @@ def to_representation(self, instance):
221248
def create(self, validated_data):
222249
dataset = models.DataSet.objects.get(id=validated_data.pop("dataset"))
223250
operations_tree = None
224-
derived_quantity = None
225251
references = None
226252
if "operation_tree" in validated_data:
227253
operations_tree = validated_data.pop("operation_tree")
228-
if "derived_quantity" in validated_data:
229-
derived_quantity = models.Quantity.objects.get(
230-
id=validated_data.pop("derived_quantity")
231-
)
232-
if "references" in validated_data:
233-
references = validated_data.pop("references")
234-
quantity = models.Quantity.objects.create(
235-
dataset=dataset, derived_quantity=derived_quantity, **validated_data
236-
)
254+
if "history" in validated_data:
255+
history = validated_data.pop("history")
256+
if history and "references" in history:
257+
references = history.pop("references")
258+
quantity = models.Quantity.objects.create(dataset=dataset, **validated_data)
237259
if operations_tree:
238260
operations_tree["quantity"] = quantity.id
239261
OperationTreeSerializer.create(
@@ -242,7 +264,9 @@ def create(self, validated_data):
242264
if references:
243265
for ref in references:
244266
ref["derived_quantity"] = quantity.id
245-
QuantitySerializer.create(QuantitySerializer(), validated_data=ref)
267+
ReferenceQuantitySerializer.create(
268+
ReferenceQuantitySerializer(), validated_data=ref
269+
)
246270
return quantity
247271

248272

0 commit comments

Comments
 (0)