Coverage for apis_core/apis_entities/models.py: 62%
56 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-09-03 06:15 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-09-03 06:15 +0000
1import functools
2import logging
3import re
5from django.conf import settings
6from django.db.models.base import ModelBase
7from django.urls import NoReverseMatch, reverse
9from apis_core.apis_metainfo.models import RootObject
10from apis_core.utils.settings import apis_base_uri
12NEXT_PREV = getattr(settings, "APIS_NEXT_PREV", True)
14logger = logging.getLogger(__name__)
17class AbstractEntityModelBase(ModelBase):
18 def __new__(metacls, name, bases, attrs):
19 if name == "AbstractEntity":
20 return super().__new__(metacls, name, bases, attrs)
21 else:
22 new_class = super().__new__(metacls, name, bases, attrs)
23 if not new_class._meta.ordering:
24 logger.warning(
25 f"{name} inherits from AbstractEntity but does not specify 'ordering' in its Meta class. "
26 "Empty ordering could result in inconsitent results with pagination. "
27 "Set a ordering or inherit the Meta class from AbstractEntity.",
28 )
30 return new_class
33class AbstractEntity(RootObject, metaclass=AbstractEntityModelBase):
34 """
35 Abstract super class which encapsulates common logic between the
36 different entity kinds and provides various methods relating to either
37 all or one specific entity kind.
39 Most of the class methods are designed to be used in the subclass as they
40 are considering contexts which depend on the subclass entity type.
41 So they are to be understood in that dynamic context.
42 """
44 class Meta:
45 abstract = True
47 @classmethod
48 def get_or_create_uri(cls, uri):
49 uri = str(uri)
50 try:
51 if re.match(r"^[0-9]*$", uri):
52 p = cls.objects.get(pk=uri)
53 else:
54 p = cls.objects.get(uri__uri=uri)
55 return p
56 except Exception as e:
57 print("Found no object corresponding to given uri." + e)
58 return False
60 # TODO
61 @classmethod
62 def get_entity_list_filter(cls):
63 return None
65 @functools.cached_property
66 def get_prev_id(self):
67 if NEXT_PREV:
68 prev_instance = (
69 type(self)
70 .objects.filter(id__lt=self.id)
71 .order_by("-id")
72 .only("id")
73 .first()
74 )
75 if prev_instance is not None:
76 return prev_instance.id
77 return False
79 @functools.cached_property
80 def get_next_id(self):
81 if NEXT_PREV:
82 next_instance = (
83 type(self)
84 .objects.filter(id__gt=self.id)
85 .order_by("id")
86 .only("id")
87 .first()
88 )
89 if next_instance is not None:
90 return next_instance.id
91 return False
93 def get_default_uri(self):
94 try:
95 route = reverse("GetEntityGenericRoot", kwargs={"pk": self.pk})
96 except NoReverseMatch:
97 route = reverse("apis_core:GetEntityGeneric", kwargs={"pk": self.pk})
98 base = apis_base_uri().strip("/")
99 return f"{base}{route}"