Coverage for apis_core/entities/abc.py: 72%
94 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-28 06:34 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-28 06:34 +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 class Config(GenericModel.Config):
19 overview_section = _("Entities")
21 @property
22 def get_canonical_url(self):
23 return reverse("apis_core:canonical-entity", args=[self.pk])
25 @functools.cached_property
26 def get_prev_id(self):
27 prev_instance = (
28 type(self).objects.filter(id__lt=self.id).order_by("-id").only("id").first()
29 )
30 if prev_instance is not None:
31 return prev_instance.id
32 return False
34 @functools.cached_property
35 def get_next_id(self):
36 next_instance = (
37 type(self).objects.filter(id__gt=self.id).order_by("id").only("id").first()
38 )
39 if next_instance is not None:
40 return next_instance.id
41 return False
43 def import_data(self, data):
44 super().import_data(data)
45 if "same_as" in data:
46 self._uris = data["same_as"]
47 self.save()
48 if "relations" in data:
49 self.create_relations_to_uris = data["relations"]
50 self.save()
53#########################
54# Abstract base classes #
55#########################
58# These abstract base classes are named after
59# CIDOC CRM entities, but we are *NOT*(!)
60# trying to implement CIDOC CRM in Django.
63class E21_Person(Entity):
64 forename = models.CharField(
65 blank=True, default="", max_length=4096, verbose_name=_("forename")
66 )
67 surname = models.CharField(
68 blank=True, default="", max_length=4096, verbose_name=_("surname")
69 )
70 gender = models.CharField(
71 blank=True, default="", max_length=4096, verbose_name=_("gender")
72 )
73 date_of_birth = models.DateField(
74 blank=True, null=True, verbose_name=_("date of birth")
75 )
76 date_of_death = models.DateField(
77 blank=True, null=True, verbose_name=_("date of death")
78 )
80 class Meta:
81 abstract = True
82 verbose_name = _("person")
83 verbose_name_plural = _("persons")
84 ordering = ["surname", "forename"]
86 def __str__(self):
87 if self.forename and self.surname:
88 return f"{self.forename} {self.surname}"
89 return self.forename or self.surname or force_str(_("No name"))
91 import_definitions = {
92 "https://d-nb.info/*|/.*.rdf": lambda x: load_uri_using_path(
93 x, person.E21_PersonFromDNB
94 ),
95 "http://www.wikidata.org/*|/.*.rdf": lambda x: load_uri_using_path(
96 x, person.E21_PersonFromWikidata
97 ),
98 }
100 @classmethod
101 def get_rdf_types(cls):
102 return [CRM.E21_Person]
105class E53_Place(Entity):
106 """
107 The feature_code field refers to the geonames feature codes, as
108 listed on https://www.geonames.org/export/codes.html
109 """
111 label = models.CharField(
112 blank=True, default="", max_length=4096, verbose_name=_("label")
113 )
114 latitude = models.FloatField(blank=True, null=True, verbose_name=_("latitude"))
115 longitude = models.FloatField(blank=True, null=True, verbose_name=_("longitude"))
116 feature_code = models.CharField(
117 blank=True,
118 default="",
119 max_length=16,
120 verbose_name=_("feature code"),
121 help_text='<a href="https://www.geonames.org/export/codes.html" target="_blank">Geonames Feature Code List</a>',
122 )
124 class Meta:
125 abstract = True
126 verbose_name = _("place")
127 verbose_name_plural = _("places")
128 ordering = ["label"]
130 def __str__(self):
131 return self.label or force_str(_("No label"))
133 import_definitions = {
134 "https://d-nb.info/*|/.*.rdf": lambda x: load_uri_using_path(
135 x, place.E53_PlaceFromDNB
136 ),
137 "https://sws.geonames.org/*|/.*.rdf*": lambda x: load_uri_using_path(
138 x, place.E53_PlaceFromGeonames
139 ),
140 "http://www.wikidata.org/*|/.*.rdf": lambda x: load_uri_using_path(
141 x, place.E53_PlaceFromWikidata
142 ),
143 }
145 @classmethod
146 def get_rdf_types(cls):
147 return [CRM.E53_Place]
149 @classmethod
150 def create_from_string(cls, string):
151 return cls.objects.create(label=string)
154class E74_Group(Entity):
155 label = models.CharField(
156 blank=True, default="", max_length=4096, verbose_name=_("label")
157 )
159 class Meta:
160 abstract = True
161 verbose_name = _("group")
162 verbose_name_plural = _("groups")
163 ordering = ["label"]
165 def __str__(self):
166 return self.label or force_str(_("No label"))
168 import_definitions = {
169 "https://d-nb.info/*|/.*.rdf": lambda x: load_uri_using_path(
170 x, group.E74_GroupFromDNB
171 ),
172 "http://www.wikidata.org/*|/.*.rdf": lambda x: load_uri_using_path(
173 x, group.E74_GroupFromWikidata
174 ),
175 }
177 @classmethod
178 def get_rdf_types(cls):
179 return [CRM.E74_Group]
181 @classmethod
182 def create_from_string(cls, string):
183 return cls.objects.create(label=string)
186class SimpleLabelEntity(SimpleLabelModel, Entity):
187 class Meta(SimpleLabelModel.Meta):
188 abstract = True