Coverage for apis_core/entities/abc.py: 72%
92 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-07-06 07:19 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-07-06 07:19 +0000
1import functools
3from django.db import models
4from django.urls import reverse
5from django.utils.encoding import force_str
6from django.utils.translation import gettext_lazy as _
8from apis_core.entities.rdfconfigs import group, person, place
9from apis_core.generic.abc import GenericModel, SimpleLabelModel
10from apis_core.generic.utils.rdf_namespace import CRM
11from apis_core.utils.rdf import load_uri_using_path
14class Entity(GenericModel):
15 class Meta:
16 abstract = True
18 @property
19 def get_canonical_url(self):
20 return reverse("apis_core:canonical-entity", args=[self.pk])
22 @functools.cached_property
23 def get_prev_id(self):
24 prev_instance = (
25 type(self).objects.filter(id__lt=self.id).order_by("-id").only("id").first()
26 )
27 if prev_instance is not None:
28 return prev_instance.id
29 return False
31 @functools.cached_property
32 def get_next_id(self):
33 next_instance = (
34 type(self).objects.filter(id__gt=self.id).order_by("id").only("id").first()
35 )
36 if next_instance is not None:
37 return next_instance.id
38 return False
40 def import_data(self, data):
41 super().import_data(data)
42 if "same_as" in data:
43 self._uris = data["same_as"]
44 self.save()
45 if "relations" in data:
46 self.create_relations_to_uris = data["relations"]
47 self.save()
50#########################
51# Abstract base classes #
52#########################
55# These abstract base classes are named after
56# CIDOC CRM entities, but we are *NOT*(!)
57# trying to implement CIDOC CRM in Django.
60class E21_Person(Entity):
61 forename = models.CharField(
62 blank=True, default="", max_length=4096, verbose_name=_("forename")
63 )
64 surname = models.CharField(
65 blank=True, default="", max_length=4096, verbose_name=_("surname")
66 )
67 gender = models.CharField(
68 blank=True, default="", max_length=4096, verbose_name=_("gender")
69 )
70 date_of_birth = models.DateField(
71 blank=True, null=True, verbose_name=_("date of birth")
72 )
73 date_of_death = models.DateField(
74 blank=True, null=True, verbose_name=_("date of death")
75 )
77 class Meta:
78 abstract = True
79 verbose_name = _("person")
80 verbose_name_plural = _("persons")
81 ordering = ["surname", "forename"]
83 def __str__(self):
84 if self.forename and self.surname:
85 return f"{self.forename} {self.surname}"
86 return self.forename or self.surname or force_str(_("No name"))
88 import_definitions = {
89 "https://d-nb.info/*|/.*.rdf": lambda x: load_uri_using_path(
90 x, person.E21_PersonFromDNB
91 ),
92 "http://www.wikidata.org/*|/.*.rdf": lambda x: load_uri_using_path(
93 x, person.E21_PersonFromWikidata
94 ),
95 }
97 @classmethod
98 def get_rdf_types(cls):
99 return [CRM.E21_Person]
102class E53_Place(Entity):
103 """
104 The feature_code field refers to the geonames feature codes, as
105 listed on https://www.geonames.org/export/codes.html
106 """
108 label = models.CharField(
109 blank=True, default="", max_length=4096, verbose_name=_("label")
110 )
111 latitude = models.FloatField(blank=True, null=True, verbose_name=_("latitude"))
112 longitude = models.FloatField(blank=True, null=True, verbose_name=_("longitude"))
113 feature_code = models.CharField(
114 blank=True,
115 default="",
116 max_length=16,
117 verbose_name=_("feature code"),
118 help_text='<a href="https://www.geonames.org/export/codes.html" target="_blank">Geonames Feature Code List</a>',
119 )
121 class Meta:
122 abstract = True
123 verbose_name = _("place")
124 verbose_name_plural = _("places")
125 ordering = ["label"]
127 def __str__(self):
128 return self.label or force_str(_("No label"))
130 import_definitions = {
131 "https://d-nb.info/*|/.*.rdf": lambda x: load_uri_using_path(
132 x, place.E53_PlaceFromDNB
133 ),
134 "https://sws.geonames.org/*|/.*.rdf*": lambda x: load_uri_using_path(
135 x, place.E53_PlaceFromGeonames
136 ),
137 "http://www.wikidata.org/*|/.*.rdf": lambda x: load_uri_using_path(
138 x, place.E53_PlaceFromWikidata
139 ),
140 }
142 @classmethod
143 def get_rdf_types(cls):
144 return [CRM.E53_Place]
146 @classmethod
147 def create_from_string(cls, string):
148 return cls.objects.create(label=string)
151class E74_Group(Entity):
152 label = models.CharField(
153 blank=True, default="", max_length=4096, verbose_name=_("label")
154 )
156 class Meta:
157 abstract = True
158 verbose_name = _("group")
159 verbose_name_plural = _("groups")
160 ordering = ["label"]
162 def __str__(self):
163 return self.label or force_str(_("No label"))
165 import_definitions = {
166 "https://d-nb.info/*|/.*.rdf": lambda x: load_uri_using_path(
167 x, group.E74_GroupFromDNB
168 ),
169 "http://www.wikidata.org/*|/.*.rdf": lambda x: load_uri_using_path(
170 x, group.E74_GroupFromWikidata
171 ),
172 }
174 @classmethod
175 def get_rdf_types(cls):
176 return [CRM.E74_Group]
178 @classmethod
179 def create_from_string(cls, string):
180 return cls.objects.create(label=string)
183class SimpleLabelEntity(SimpleLabelModel, Entity):
184 class Meta(SimpleLabelModel.Meta):
185 abstract = True