Coverage for apis_core/collections/models.py: 69%
39 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-06-25 10:00 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-06-25 10:00 +0000
1from django.contrib.contenttypes.fields import GenericForeignKey
2from django.contrib.contenttypes.models import ContentType
3from django.db import models
5from apis_core.generic.abc import GenericModel
8class SkosCollectionManager(models.Manager):
9 def by_instance(self, instance):
10 content_type = ContentType.objects.get_for_model(instance)
11 scco = SkosCollectionContentObject.objects.filter(
12 content_type=content_type, object_id=instance.id
13 )
14 return self.get_queryset().filter(
15 pk__in=scco.values_list("collection", flat=True)
16 )
19class SkosCollection(GenericModel, models.Model):
20 """
21 SKOS collections are labeled and/or ordered groups of SKOS concepts.
22 Collections are useful where a group of concepts shares something in common,
23 and it is convenient to group them under a common label, or
24 where some concepts can be placed in a meaningful order.
26 Miles, Alistair, and Sean Bechhofer. "SKOS simple knowledge
27 organization system reference. W3C recommendation (2009)."
29 """
31 class Meta:
32 ordering = ["name"]
34 name = models.CharField(
35 max_length=300,
36 verbose_name="skos:prefLabel",
37 help_text="Collection label or name",
38 )
39 label_lang = models.CharField(
40 max_length=3,
41 blank=True,
42 default="en",
43 verbose_name="skos:prefLabel language",
44 help_text="Language of preferred label given above",
45 )
46 creator = models.TextField(
47 blank=True,
48 verbose_name="dc:creator",
49 help_text="Person or organisation that created this collection"
50 "If more than one list all using a semicolon ;",
51 )
52 contributor = models.TextField(
53 blank=True,
54 verbose_name="dc:contributor",
55 help_text="Person or organisation that made contributions to the collection"
56 "If more than one list all using a semicolon ;",
57 )
58 objects = SkosCollectionManager()
60 def __str__(self):
61 return self.name
63 def add(self, instance: object):
64 content_type = ContentType.objects.get_for_model(instance)
65 SkosCollectionContentObject.objects.get_or_create(
66 collection=self, content_type=content_type, object_id=instance.pk
67 )
69 def remove(self, instance: object):
70 content_type = ContentType.objects.get_for_model(instance)
71 SkosCollectionContentObject.objects.filter(
72 collection=self, content_type=content_type, object_id=instance.pk
73 ).delete()
75 @property
76 def parent_collection(self):
77 content_type = ContentType.objects.get_for_model(self)
78 sccos = SkosCollectionContentObject.objects.filter(
79 content_type=content_type, object_id=self.id
80 )
81 if len(sccos) == 1:
82 return sccos.first().collection
83 raise SkosCollection.MultipleObjectsReturned(
84 f'"{self}" is part of multiple collections'
85 )
88class SkosCollectionContentObject(GenericModel, models.Model):
89 """
90 *Throughtable* datamodel to connect collections to arbitrary content
91 """
93 collection = models.ForeignKey(SkosCollection, on_delete=models.CASCADE)
95 content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
96 object_id = models.PositiveIntegerField()
97 content_object = GenericForeignKey("content_type", "object_id")
99 def __str__(self):
100 return f"{self.content_object} -> {self.collection}"