Coverage for operatingsystem/models.py: 88%
85 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-24 19:06 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-24 19:06 +0000
1from django.db import models
2from django.db.models import Q
3from django.urls import reverse
4from simple_history.models import HistoricalRecords
5from vendor.models import Model as VendorModel
6from django.contrib.auth.models import Group
7from taggit.managers import TaggableManager
9from django.core.exceptions import ObjectDoesNotExist
11from . import app_label
14class Manager(models.Manager):
15 """
16 Special manager to ease the access to Operatingsystem objects
17 eg. RHEL6.1, RHEL 6.1, SLES10, SLES 10.1 should all work well
18 """
20 def get_by_natural_key(self, vendor=None, version=None):
21 """
22 Ease access to OS objects, by providing a lot of different options
23 to query for 'em. See also operatingsystem.models.Manager.__doc__
24 :model:`sm.operatingsystem.models.Manager`
25 """
26 if vendor is None and version is None:
27 raise ObjectDoesNotExist("Nothing to query")
29 # Handle natural key tuple if passed as single arg (Django's default)
30 if version is None and isinstance(vendor, (list, tuple)):
31 version = vendor[1]
32 vendor = vendor[0]
34 vendorobj = None
35 try:
36 if isinstance(vendor, str):
37 # When using natural keys during loaddata, we don't have a
38 # group context easily but for global/initial ones, they
39 # might be in a specific group or null group.
40 # For now, we search all vendors.
41 vendorobj = VendorModel.objects.filter(name=vendor).first()
42 else:
43 vendorobj = vendor
44 except Exception:
45 pass
46 object = None
47 try:
48 object = self.get(vendor=vendorobj, version=version)
49 return object
50 except Exception:
51 pass
53 if version is None and vendor is not None:
54 version = vendor
55 vendor = None
57 if object is None and not isinstance(version, (tuple, list, dict)):
58 if version[0:7] == "Red Hat":
59 vendorobj = VendorModel.objects.filter(name="Red Hat").first()
60 vers = version[7:].lstrip()
61 if len(vers) == 1:
62 vers += ".0"
63 object = self.get(vendor=vendorobj, version=vers)
64 elif version[0:4] == "RHEL":
65 vendorobj = VendorModel.objects.filter(name="Red Hat").first()
66 vers = version[4:].lstrip()
67 if len(vers) == 1:
68 vers += ".0"
69 object = self.get(vendor=vendorobj, version=vers)
70 elif version[0:4] == "SUSE" or version[0:4] == "SLES":
71 vendorobj = VendorModel.objects.filter(name="Novell").first()
72 object = self.get(vendor=vendorobj, version=version[4:].lstrip())
73 elif isinstance(version, (tuple, list)):
74 try:
75 vendorobj = VendorModel.objects.filter(name=version[0]).first()
76 object = self.get(vendor=vendorobj, version=version[1])
77 return object
78 except Exception as e: # pragma: no cover
79 print("Exception: %s" % e) # pragma: no cover
80 pass # pragma: no cover
81 else:
82 raise Exception("No idea how to handle query with %s" % version.__class__)
84 if object is None:
85 vendorobj = VendorModel.objects.filter(name=vendor).first()
86 object = self.get(vendor=vendorobj, version=version)
88 return object
91class Model(models.Model):
92 objects = Manager()
93 version = models.CharField(max_length=45)
94 vendor = models.ForeignKey(
95 VendorModel,
96 null=False,
97 default=None,
98 related_name="%s_set" % app_label,
99 related_query_name="%s" % app_label,
100 on_delete=models.PROTECT,
101 )
103 group = models.ForeignKey(
104 Group,
105 editable=False,
106 blank=True,
107 null=True,
108 on_delete=models.PROTECT,
109 related_name="operatingsystems",
110 )
112 tags = TaggableManager(blank=True, related_name="operatingsystem_tags")
114 history = HistoricalRecords()
116 def __str__(self):
117 try:
118 vendor = self.vendor.name
119 except ObjectDoesNotExist:
120 vendor = "?"
121 return "{} {}".format(vendor, self.version)
123 def natural_key(self):
124 return self.vendor.natural_key() + (self.version,)
126 natural_key.dependencies = ["vendor.Model"]
128 @classmethod
129 def get_natural_key_fields(cls):
130 return ["vendor__name", "version"]
132 @classmethod
133 def get_natural_key_info(cls):
134 return [("vendor", VendorModel), ("version", None)]
136 def get_absolute_url(self):
137 return reverse("%s:detail" % app_label, kwargs={"pk": self.pk})
139 class Meta:
140 db_table = "{}_{}".format("sm", app_label)
141 constraints = [
142 models.UniqueConstraint(
143 fields=["vendor", "version", "group"],
144 name="unique_sm_operatingsystem_vendor_version_group",
145 ),
146 # PostgreSQL treats NULLs as distinct, so the constraint above
147 # cannot deduplicate global (group=NULL) rows. Keep reference
148 # data globally unique with a partial constraint.
149 models.UniqueConstraint(
150 fields=["vendor", "version"],
151 condition=Q(group__isnull=True),
152 name="unique_sm_operatingsystem_global_vendor_version",
153 ),
154 ]