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

1from django.contrib.contenttypes.fields import GenericForeignKey 

2from django.contrib.contenttypes.models import ContentType 

3from django.db import models 

4 

5from apis_core.generic.abc import GenericModel 

6 

7 

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 ) 

17 

18 

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. 

25 

26 Miles, Alistair, and Sean Bechhofer. "SKOS simple knowledge 

27 organization system reference. W3C recommendation (2009)." 

28 

29 """ 

30 

31 class Meta: 

32 ordering = ["name"] 

33 

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() 

59 

60 def __str__(self): 

61 return self.name 

62 

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 ) 

68 

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() 

74 

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 ) 

86 

87 

88class SkosCollectionContentObject(GenericModel, models.Model): 

89 """ 

90 *Throughtable* datamodel to connect collections to arbitrary content 

91 """ 

92 

93 collection = models.ForeignKey(SkosCollection, on_delete=models.CASCADE) 

94 

95 content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) 

96 object_id = models.PositiveIntegerField() 

97 content_object = GenericForeignKey("content_type", "object_id") 

98 

99 def __str__(self): 

100 return f"{self.content_object} -> {self.collection}"