Coverage for operatingsystem/models.py: 88%

85 statements  

« 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 

8 

9from django.core.exceptions import ObjectDoesNotExist 

10 

11from . import app_label 

12 

13 

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 """ 

19 

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

28 

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] 

33 

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 

52 

53 if version is None and vendor is not None: 

54 version = vendor 

55 vendor = None 

56 

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

83 

84 if object is None: 

85 vendorobj = VendorModel.objects.filter(name=vendor).first() 

86 object = self.get(vendor=vendorobj, version=version) 

87 

88 return object 

89 

90 

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 ) 

102 

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 ) 

111 

112 tags = TaggableManager(blank=True, related_name="operatingsystem_tags") 

113 

114 history = HistoricalRecords() 

115 

116 def __str__(self): 

117 try: 

118 vendor = self.vendor.name 

119 except ObjectDoesNotExist: 

120 vendor = "?" 

121 return "{} {}".format(vendor, self.version) 

122 

123 def natural_key(self): 

124 return self.vendor.natural_key() + (self.version,) 

125 

126 natural_key.dependencies = ["vendor.Model"] 

127 

128 @classmethod 

129 def get_natural_key_fields(cls): 

130 return ["vendor__name", "version"] 

131 

132 @classmethod 

133 def get_natural_key_info(cls): 

134 return [("vendor", VendorModel), ("version", None)] 

135 

136 def get_absolute_url(self): 

137 return reverse("%s:detail" % app_label, kwargs={"pk": self.pk}) 

138 

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 ]