Skip to content

io_resources

main.io_resources ¤

Django import / export Resource classes for facillitating DB Import and Export.

Classes¤

CompetencyDomainResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting CompetencyDomains.

Classes¤
Meta ¤

Meta options for CompetencyDomainResource.

CompetencyResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting Competencies.

Classes¤
Meta ¤

Meta options for CompetencyResource.

LearningResourceResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting LearningResource.

Classes¤
Meta ¤

Meta options for LearningResourceResource.

MultipleChoiceWidget(separator='|', **kwargs) ¤

Bases: CharWidget

A CharWidget that allows for multiple values to work with MultiSelectField.

Override the constructor to set a separator, defaults to |.

Source code in main/io_resources.py
90
91
92
93
def __init__(self, separator: str = "|", **kwargs: Any) -> None:
    """Override the constructor to set a separator, defaults to `|`."""
    self.separator = separator
    super().__init__(**kwargs)
Methods:¤
clean(value, row=None, **kwargs) ¤

Override the clean method to make the choices comma-separated.

This is required for the MultiSelectField to work.

Source code in main/io_resources.py
 95
 96
 97
 98
 99
100
101
102
def clean(
    self, value: str, row: Mapping[str, Any] | None = None, **kwargs: Any
) -> str | None:
    """Override the clean method to make the choices comma-separated.

    This is required for the MultiSelectField to work.
    """
    return super().clean(value.replace(self.separator, ","), row, **kwargs)
render(value, obj=None, **kwargs) ¤

Override the render method so the correct separator is used on export.

Source code in main/io_resources.py
104
105
106
def render(self, value: list, obj: Model | None = None, **kwargs: Any) -> Any:
    """Override the render method so the correct separator is used on export."""
    return super().render(self.separator.join(value), obj, **kwargs)

ProviderResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting Provider.

Classes¤
Meta ¤

Meta options for ProviderResource.

SkillLevelResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting SkillLevels.

Classes¤
Meta ¤

Meta options for SkillLevelResource.

SkillResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting Skills.

Classes¤
Meta ¤

Meta options for SkillResource.

Methods:¤
after_import(dataset, result, **kwargs) ¤

Override the after_import method to ensure that related_skills are linked.

This approach was inspired by https://github.com/django-import-export/django-import-export/issues/397#issuecomment-1034928530

Source code in main/io_resources.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
def after_import(self, dataset: Dataset, result: Result, **kwargs: Any) -> None:
    """Override the after_import method to ensure that related_skills are linked.

    This approach was inspired by
    https://github.com/django-import-export/django-import-export/issues/397#issuecomment-1034928530
    """
    for i, skill_dict in enumerate(dataset.dict, 1):
        skill = Skill.objects.get(slug=skill_dict["slug"])
        related_skills = filter(
            None, skill_dict.get("related_skills", "").split("|")
        )
        for related_skill_slug in related_skills:
            try:
                related_skill = Skill.objects.get(slug=related_skill_slug)
            except Skill.DoesNotExist:
                result.append_invalid_row(
                    i,
                    skill_dict,
                    ValidationError(
                        {
                            "related_skills": _(
                                f"The skill does not exist: {related_skill_slug}"
                            )
                        }
                    ),
                )
            skill.related_skills.add(related_skill)

            if result.rows[i - 1].import_type == "new":
                # Update the diff display in the admin page
                diff = self.get_diff_class()(self, Skill(), True)  # type: ignore[arg-type]
                diff.compare_with(self, skill)
                col_idx = result.diff_headers.index("related_skills")
                result.rows[i - 1].diff[col_idx] = diff.as_html()[col_idx]  # type: ignore[index]

    super().after_import(dataset, result, **kwargs)

SluggedFKWidget(model, column_name, **kwargs) ¤

Bases: ForeignKeyWidget

A ForeignKeyWidget that always uses slug as the field.

Override the constructor to set the field to slug.

Source code in main/io_resources.py
30
31
32
33
34
35
def __init__(
    self, model: type[SluggedModel], column_name: str, **kwargs: Any
) -> None:
    """Override the constructor to set the field to slug."""
    self.column_name = column_name
    super().__init__(model, field="slug", **kwargs)
Methods:¤
clean(value, row=None, **kwargs) ¤

Overwrite the clean method so that it raises and error on missing objects.

Source code in main/io_resources.py
37
38
39
40
41
42
43
44
def clean(
    self, value: str, row: Mapping[str, Any] | None = None, **kwargs: Any
) -> Any:
    """Overwrite the clean method so that it raises and error on missing objects."""
    try:
        return super().clean(value, row=row, **kwargs)
    except ObjectDoesNotExist as e:
        raise ValidationError({self.column_name: _(force_str(e))})

SluggedM2MWidget(model, column_name, ignore_missing=False, **kwargs) ¤

Bases: ManyToManyWidget

A ManyToManyWidget that always uses slug as the field, separated by |.

Override the constructor to set the field to slug and the separator to |.

Source code in main/io_resources.py
50
51
52
53
54
55
56
57
58
59
60
def __init__(
    self,
    model: type[SluggedModel],
    column_name: str,
    ignore_missing: bool = False,
    **kwargs: Any,
) -> None:
    """Override the constructor to set the field to slug and the separator to |."""
    self.column_name = column_name
    self.ignore_missing = ignore_missing
    super().__init__(model, field="slug", separator="|", **kwargs)
Methods:¤
clean(value, row=None, **kwargs) ¤

Overwrite the clean method so that it raises and error on missing objects.

This does not prevent the instance from being saved if dry_run=False on import!

Source code in main/io_resources.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def clean(
    self, value: str, row: Mapping[str, Any] | None = None, **kwargs: Any
) -> Any:
    """Overwrite the clean method so that it raises and error on missing objects.

    This does not prevent the instance from being saved if dry_run=False on import!
    """
    queryset = super().clean(value, row=row, **kwargs)
    slugs = set(filter(None, value.split(self.separator)))
    if queryset.count() == len(slugs) or self.ignore_missing:
        return queryset

    missing = slugs.symmetric_difference(
        queryset.values_list(self.field, flat=True)
    )

    raise ValidationError(
        {
            self.column_name: _(
                f"The following slugs do not exist: {', '.join(missing)}"
            )
        }
    )

ToolLanguageMethodologyResource ¤

Bases: ModelResource

A ModelResource to facilitate importing and exporting Tools.

Classes¤
Meta ¤

Meta options for ToolLanguageMethodologyResource.

Functions:¤

export_framework() ¤

Exports the core framework into one dictionary with each model as a key.

Returns:

Type Description
dict[str, list[dict[str, str]]]

A dictionary containing the entire framework. Each model is labelled by a key and is a list of dictionaries. This is JSON compatible.

Source code in main/io_resources.py
262
263
264
265
266
267
268
269
270
271
272
273
274
def export_framework() -> dict[str, list[dict[str, str]]]:
    """Exports the core framework into one dictionary with each model as a key.

    Returns:
        A dictionary containing the entire framework. Each model is labelled by a key
            and is a list of dictionaries. This is JSON compatible.
    """
    return dict(
        competency_domains=CompetencyDomainResource().export().dict,
        competencies=CompetencyResource().export().dict,
        skills=SkillResource().export().dict,
        skill_levels=SkillLevelResource().export().dict,
    )