Skip to content

Commit

Permalink
fix(data): update field values in database
Browse files Browse the repository at this point in the history
Update temporal_frequency field values in the database
following update to (forgotten) single TemporalFrequency
TextChoices value in models.py to fix potential data
divergence.
  • Loading branch information
koeaw committed Sep 19, 2024
1 parent 3910a4a commit 1156d44
Showing 1 changed file with 113 additions and 0 deletions.
113 changes: 113 additions & 0 deletions apis_ontology/migrations/0087_data_migration_fix_textchoices_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
Data migration to update DB values of `Work` entity`temporal_frequency` field
following the discovery that one `TextChoices` value was not updated
from English to German in models.py.
Reuses migration 0084's most pared down value conversion approach so far.
"""

# Generated by Django 4.2.15 on 2024-09-19 08:07

import logging
from functools import partial

from django.db import migrations


logger = logging.getLogger(__name__)

# list of dicts containing old and new field (string) values
TEMPORAL_FREQUENCY_VALUES = [ # TemporalFrequency TextChoices in models
{
"old": "singulative",
"new": "singulativ",
},
]

# list of dicts linking fields with field value dicts and models they appear in
UPDATE_FIELDS = [
{
"models": ["Work", "VersionWork"],
"fields": [
{
"name": "temporal_frequency",
"values": TEMPORAL_FREQUENCY_VALUES,
},
],
},
]


def update_field_values(apps, schema_editor, from_key="old", to_key="new"):
"""
Replace existing field values in the database with new values if
they match a given string.
Assumes affected fields contain strings (CharField, TextField,...)
or a list of strings (PostgreSQL ArrayField with a string field for
base_field).
:param from_key: identifier for current value in field value dict
:type from_key: str
:param to_key: identifier for replacement value in field value dict
:type to_key: str
"""

for item in UPDATE_FIELDS:
for model in item["models"]:
model_class = apps.get_model("apis_ontology", model)

for obj in model_class.objects.all():
for field in item["fields"]:
field_name = field["name"]
field_values = field["values"]

field_data = getattr(obj, field_name, None)

if field_data:
converted_data = field_data

if isinstance(field_data, str):
for c in field_values:
if field_data == c[from_key]:
converted_data = c[to_key]

if isinstance(field_data, list):
converted_data = []
for value in field_data:
for c in field_values:
if value == c[from_key]:
value = c[to_key]
converted_data.append(value)

if converted_data != field_data:
setattr(obj, field_name, converted_data)

# log value conversions
logger.info(
f"Converted: {','.join(field_data) if isinstance(field_data, list) else field_data} "
f"-> {','.join(converted_data) if isinstance(converted_data, list) else converted_data} "
f"({model}, ID: {getattr(obj, 'id', [])})"
)

if hasattr(obj, "skip_history_when_saving"):
obj.skip_history_when_saving = True

obj.save()


class Migration(migrations.Migration):
dependencies = [
("apis_ontology", "0086_alter_versionwork_temporal_frequency_and_more"),
]

operations = [
migrations.RunPython(
code=update_field_values,
reverse_code=partial(
update_field_values,
from_key="new",
to_key="old",
),
),
]

0 comments on commit 1156d44

Please sign in to comment.