Coverage for apis_core/generic/abc.py: 63%

79 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-22 07:51 +0000

1from django.contrib.contenttypes.models import ContentType 

2from django.db.models import BooleanField, CharField, TextField 

3from django.urls import reverse 

4 

5from apis_core.generic.helpers import permission_fullname 

6 

7 

8class GenericModel: 

9 def __repr__(self): 

10 return super().__repr__() + f" (ID: {self.id})" 

11 

12 @classmethod 

13 def get_listview_url(cls): 

14 ct = ContentType.objects.get_for_model(cls) 

15 return reverse("apis_core:generic:list", args=[ct]) 

16 

17 @classmethod 

18 def get_createview_url(cls): 

19 ct = ContentType.objects.get_for_model(cls) 

20 return reverse("apis_core:generic:create", args=[ct]) 

21 

22 @classmethod 

23 def get_importview_url(cls): 

24 ct = ContentType.objects.get_for_model(cls) 

25 return reverse("apis_core:generic:import", args=[ct]) 

26 

27 def get_edit_url(self): 

28 ct = ContentType.objects.get_for_model(self) 

29 return reverse("apis_core:generic:update", args=[ct, self.id]) 

30 

31 def get_enrich_url(self): 

32 ct = ContentType.objects.get_for_model(self) 

33 return reverse("apis_core:generic:enrich", args=[ct, self.id]) 

34 

35 def get_absolute_url(self): 

36 ct = ContentType.objects.get_for_model(self) 

37 return reverse("apis_core:generic:detail", args=[ct, self.id]) 

38 

39 def get_delete_url(self): 

40 ct = ContentType.objects.get_for_model(self) 

41 return reverse("apis_core:generic:delete", args=[ct, self.id]) 

42 

43 def get_merge_url(self, other_id): 

44 ct = ContentType.objects.get_for_model(self) 

45 return reverse("apis_core:generic:merge", args=[ct, self.id, other_id]) 

46 

47 def get_create_success_url(self): 

48 return self.get_absolute_url() 

49 

50 def get_update_success_url(self): 

51 return self.get_edit_url() 

52 

53 def get_api_detail_endpoint(self): 

54 ct = ContentType.objects.get_for_model(self) 

55 return reverse("apis_core:generic:genericmodelapi-detail", args=[ct, self.id]) 

56 

57 @classmethod 

58 def get_change_permission(self): 

59 return permission_fullname("change", self) 

60 

61 @classmethod 

62 def get_add_permission(self): 

63 return permission_fullname("add", self) 

64 

65 @classmethod 

66 def get_delete_permission(self): 

67 return permission_fullname("delete", self) 

68 

69 def get_merge_charfield_value(self, other: CharField, field: CharField): 

70 res = getattr(self, field.name) 

71 if not field.choices: 

72 otherres = getattr(other, field.name, res) 

73 if otherres != res: 

74 res += f" ({otherres})" 

75 return res 

76 

77 def get_merge_textfield_value(self, other: TextField, field: TextField): 

78 res = getattr(self, field.name) 

79 if getattr(other, field.name): 

80 res += "\n" + f"Merged from {other}:\n" + getattr(other, field.name) 

81 return res 

82 

83 def get_merge_booleanfield(self, other: BooleanField, field: BooleanField): 

84 return getattr(other, field.name) 

85 

86 def get_field_value_after_merge(self, other, field): 

87 """ 

88 This method finds the value of a field after merging `other` into `self`. 

89 It first tries to find a merge method that is specific to that field 

90 (merge_{fieldname}) and then tries to find a method that is specific to 

91 the type of the field (merge_{fieldtype}) 

92 If neither of those exist, it uses the others field value if the field 

93 in self is not set, otherwise it keeps the value in self. 

94 """ 

95 fieldtype = field.get_internal_type().lower() 

96 # if there is a `get_merge_{fieldname}` method in this model, use that one 

97 if callable(getattr(self, f"get_merge_{field.name}_value", None)): 

98 return getattr(self, f"get_merge_{field.name}_value")(other) 

99 # otherwise we check if there is a method for the field type and use that one 

100 elif callable(getattr(self, f"get_merge_{fieldtype}_value", None)): 

101 return getattr(self, f"get_merge_{fieldtype}_value")(other, field) 

102 else: 

103 if not getattr(self, field.name): 

104 return getattr(other, field.name) 

105 return getattr(self, field.name) 

106 

107 def merge_fields(self, other): 

108 """ 

109 This method iterates through the model fields and uses the 

110 `get_field_value_after_merge` method to copy values from `other` to `self`. 

111 It is called by the `merge_with` method. 

112 """ 

113 for field in self._meta.fields: 

114 newval = self.get_field_value_after_merge(other, field) 

115 if newval != getattr(self, field.name): 

116 setattr(self, field.name, newval) 

117 self.save()