Coverage for apis_core/generic/forms/__init__.py: 30%

104 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-09-03 06:15 +0000

1import logging 

2 

3from crispy_forms.helper import FormHelper 

4from crispy_forms.layout import Submit 

5from django import forms 

6from django.apps import apps 

7from django.contrib.contenttypes.models import ContentType 

8from django.urls import reverse 

9from django.utils.translation import gettext_lazy as _ 

10 

11from apis_core.core.fields import ApisModelSelect2, ApisModelSelect2Multiple 

12from apis_core.generic.abc import GenericModel 

13from apis_core.generic.forms.fields import ModelImportChoiceField 

14 

15logger = logging.getLogger(__name__) 

16 

17 

18class GenericImportForm(forms.Form): 

19 class Meta: 

20 fields = [] 

21 

22 def __init__(self, *args, **kwargs): 

23 super().__init__(*args, **kwargs) 

24 self.fields["url"] = ModelImportChoiceField( 

25 queryset=self.Meta.model.objects.all() 

26 ) 

27 ct = ContentType.objects.get_for_model(self.Meta.model) 

28 url = reverse("apis_core:generic:autocompleteexternalonly", args=[ct]) 

29 self.fields["url"].widget = ApisModelSelect2( 

30 url, attrs={"data-html": True, "data-tags": 1} 

31 ) 

32 self.fields["url"].widget.choices = self.fields["url"].choices 

33 self.helper = FormHelper() 

34 self.helper.add_input(Submit("submit", _("Submit"))) 

35 

36 

37class GenericFilterSetForm(forms.Form): 

38 """ 

39 FilterSet form for generic models 

40 Adds a submit button using the django crispy form helper 

41 Adds a `columns` selector that lists all the fields from 

42 the model 

43 """ 

44 

45 columns_exclude = [] 

46 

47 def __init__(self, *args, **kwargs): 

48 super().__init__(*args, **kwargs) 

49 

50 self.helper = FormHelper(self) 

51 self.helper.form_method = "GET" 

52 self.helper.add_input(Submit("submit", _("Submit"))) 

53 

54 def clean(self): 

55 self.cleaned_data = super().clean() 

56 self.cleaned_data.pop("columns", None) 

57 return self.cleaned_data 

58 

59 

60class GenericModelForm(forms.ModelForm): 

61 """ 

62 Model form for generic models 

63 Adds a submit button using the django crispy form helper 

64 and sets the ModelChoiceFields and ModelMultipleChoiceFields 

65 to use autocomplete replacement fields 

66 """ 

67 

68 class Meta: 

69 fields = "__all__" 

70 

71 def __init__(self, *args, **kwargs): 

72 super().__init__(*args, **kwargs) 

73 try: 

74 skoscollection = apps.get_model("collections.SkosCollection") 

75 self.fields["collections"] = forms.ModelMultipleChoiceField( 

76 required=False, 

77 queryset=skoscollection.objects.all(), 

78 label=_("Collections"), 

79 ) 

80 if instance := kwargs.get("instance"): 

81 self.fields["collections"].initial = skoscollection.objects.by_instance( 

82 instance 

83 ).values_list("pk", flat=True) 

84 except LookupError as e: 

85 logger.debug("Not adding collections to form: %s", e) 

86 

87 self.helper = FormHelper(self) 

88 self.helper.add_input(Submit("submit", _("Submit"))) 

89 

90 # override the fields pointing to other models, 

91 # to make them use the autocomplete widgets 

92 override_fieldtypes = { 

93 "ModelMultipleChoiceField": ApisModelSelect2Multiple, 

94 "ModelChoiceField": ApisModelSelect2, 

95 "ModelImportChoiceField": ApisModelSelect2, 

96 } 

97 for field in self.fields: 

98 clsname = self.fields[field].__class__.__name__ 

99 if clsname in override_fieldtypes.keys(): 

100 ct = ContentType.objects.get_for_model( 

101 self.fields[field]._queryset.model 

102 ) 

103 if issubclass(ct.model_class(), GenericModel): 

104 url = reverse("apis_core:generic:autocomplete", args=[ct]) 

105 self.fields[field].widget = override_fieldtypes[clsname]( 

106 url, attrs={"data-html": True} 

107 ) 

108 self.fields[field].widget.choices = self.fields[field].choices 

109 

110 def save(self, *args, **kwargs): 

111 instance = super().save(*args, **kwargs) 

112 try: 

113 skoscollection = apps.get_model("collections.SkosCollection") 

114 if "collections" in self.cleaned_data: 

115 collections = self.cleaned_data.get("collections") 

116 for collection in skoscollection.objects.exclude(pk__in=collections): 

117 collection.remove(instance) 

118 for collection in skoscollection.objects.filter(pk__in=collections): 

119 collection.add(instance) 

120 except LookupError as e: 

121 logger.debug("Not creating collections from form: %s", e) 

122 return instance 

123 

124 

125class GenericSelectMergeOrEnrichForm(forms.Form): 

126 def __init__(self, *args, **kwargs): 

127 if "instance" in kwargs: 

128 instance = kwargs.pop("instance") 

129 super().__init__(*args, **kwargs) 

130 ct = ContentType.objects.get_for_model(instance) 

131 self.fields["uri"] = forms.ModelChoiceField( 

132 queryset=ct.model_class().objects.all() 

133 ) 

134 uri = reverse("apis_core:generic:autocomplete", args=[ct]) 

135 attrs = {"data-html": True, "data-tags": 1} 

136 self.fields["uri"].widget = ApisModelSelect2(uri, attrs=attrs) 

137 self.fields["uri"].widget.choices = self.fields["uri"].choices 

138 self.fields["uri"].label = "Select or paste URI" 

139 self.helper = FormHelper() 

140 self.helper.form_method = "GET" 

141 self.helper.add_input(Submit("submit", _("Submit"))) 

142 self.helper.form_action = instance.get_enrich_url() 

143 

144 

145class GenericMergeWithForm(forms.Form): 

146 def __init__(self, *args, **kwargs): 

147 super().__init__(*args, **kwargs) 

148 self.helper = FormHelper() 

149 self.helper.add_input(Submit("submit", _("Merge"))) 

150 

151 

152class GenericEnrichForm(forms.Form): 

153 def __init__(self, *args, **kwargs): 

154 data = kwargs.pop("data", {}) 

155 instance = kwargs.pop("instance", None) 

156 super().__init__(*args, **kwargs) 

157 for key, value in data.items(): 

158 update_key = f"update_{key}" 

159 self.fields[update_key] = forms.BooleanField( 

160 required=False, 

161 label=f"Update {key} from {getattr(instance, key)} to {value}", 

162 ) 

163 

164 self.fields[key] = forms.CharField(initial=value, required=False) 

165 self.fields[key].widget = self.fields[key].hidden_widget() 

166 self.helper = FormHelper() 

167 self.helper.add_input(Submit("submit", _("Submit")))