Coverage for apis_core/generic/forms/__init__.py: 29%
102 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-02-19 16:54 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-02-19 16:54 +0000
1import logging
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
10from apis_core.core.fields import ApisModelSelect2, ApisModelSelect2Multiple
11from apis_core.generic.abc import GenericModel
12from apis_core.generic.forms.fields import ModelImportChoiceField
14logger = logging.getLogger(__name__)
17class GenericImportForm(forms.Form):
18 class Meta:
19 fields = []
21 def __init__(self, *args, **kwargs):
22 super().__init__(*args, **kwargs)
23 self.fields["url"] = ModelImportChoiceField(
24 queryset=self.Meta.model.objects.all()
25 )
26 ct = ContentType.objects.get_for_model(self.Meta.model)
27 url = reverse("apis_core:generic:autocompleteexternalonly", args=[ct])
28 self.fields["url"].widget = ApisModelSelect2(
29 url, attrs={"data-html": True, "data-tags": 1}
30 )
31 self.fields["url"].widget.choices = self.fields["url"].choices
32 self.helper = FormHelper()
33 self.helper.add_input(Submit("submit", "Submit"))
36class GenericFilterSetForm(forms.Form):
37 """
38 FilterSet form for generic models
39 Adds a submit button using the django crispy form helper
40 Adds a `columns` selector that lists all the fields from
41 the model
42 """
44 columns_exclude = []
46 def __init__(self, *args, **kwargs):
47 super().__init__(*args, **kwargs)
49 self.helper = FormHelper()
50 self.helper.form_method = "GET"
51 self.helper.add_input(Submit("submit", "Submit"))
53 def clean(self):
54 self.cleaned_data = super().clean()
55 self.cleaned_data.pop("columns", None)
56 return self.cleaned_data
59class GenericModelForm(forms.ModelForm):
60 """
61 Model form for generic models
62 Adds a submit button using the django crispy form helper
63 and sets the ModelChoiceFields and ModelMultipleChoiceFields
64 to use autocomplete replacement fields
65 """
67 class Meta:
68 fields = "__all__"
70 def __init__(self, *args, **kwargs):
71 super().__init__(*args, **kwargs)
72 try:
73 skoscollection = apps.get_model("collections.SkosCollection")
74 self.fields["collections"] = forms.ModelMultipleChoiceField(
75 required=False, queryset=skoscollection.objects.all()
76 )
77 if instance := kwargs.get("instance"):
78 self.fields["collections"].initial = skoscollection.objects.by_instance(
79 instance
80 ).values_list("pk", flat=True)
81 except LookupError as e:
82 logger.debug("Not adding collections to form: %s", e)
84 self.helper = FormHelper(self)
85 self.helper.add_input(Submit("submit", "Submit"))
87 # override the fields pointing to other models,
88 # to make them use the autocomplete widgets
89 override_fieldtypes = {
90 "ModelMultipleChoiceField": ApisModelSelect2Multiple,
91 "ModelChoiceField": ApisModelSelect2,
92 "ModelImportChoiceField": ApisModelSelect2,
93 }
94 for field in self.fields:
95 clsname = self.fields[field].__class__.__name__
96 if clsname in override_fieldtypes.keys():
97 ct = ContentType.objects.get_for_model(
98 self.fields[field]._queryset.model
99 )
100 if issubclass(ct.model_class(), GenericModel):
101 url = reverse("apis_core:generic:autocomplete", args=[ct])
102 self.fields[field].widget = override_fieldtypes[clsname](
103 url, attrs={"data-html": True}
104 )
105 self.fields[field].widget.choices = self.fields[field].choices
107 def save(self, *args, **kwargs):
108 instance = super().save(*args, **kwargs)
109 try:
110 skoscollection = apps.get_model("collections.SkosCollection")
111 if collections := self.cleaned_data.get("collections"):
112 for collection in skoscollection.objects.exclude(pk__in=collections):
113 collection.remove(instance)
114 for collection in skoscollection.objects.filter(pk__in=collections):
115 collection.add(instance)
116 except LookupError as e:
117 logger.debug("Not creating collections from form: %s", e)
118 return instance
121class GenericSelectMergeOrEnrichForm(forms.Form):
122 def __init__(self, *args, **kwargs):
123 if "instance" in kwargs:
124 instance = kwargs.pop("instance")
125 super().__init__(*args, **kwargs)
126 ct = ContentType.objects.get_for_model(instance)
127 self.fields["uri"] = forms.ModelChoiceField(
128 queryset=ct.model_class().objects.all()
129 )
130 uri = reverse("apis_core:generic:autocomplete", args=[ct])
131 attrs = {"data-html": True, "data-tags": 1}
132 self.fields["uri"].widget = ApisModelSelect2(uri, attrs=attrs)
133 self.fields["uri"].widget.choices = self.fields["uri"].choices
134 self.fields["uri"].label = "Select or paste URI"
135 self.helper = FormHelper()
136 self.helper.form_method = "GET"
137 self.helper.add_input(Submit("submit", "Submit"))
138 self.helper.form_action = instance.get_enrich_url()
141class GenericMergeWithForm(forms.Form):
142 def __init__(self, *args, **kwargs):
143 super().__init__(*args, **kwargs)
144 self.helper = FormHelper()
145 self.helper.add_input(Submit("submit", "Merge"))
148class GenericEnrichForm(forms.Form):
149 def __init__(self, *args, **kwargs):
150 data = kwargs.pop("data", {})
151 instance = kwargs.pop("instance", None)
152 super().__init__(*args, **kwargs)
153 for key, value in data.items():
154 update_key = f"update_{key}"
155 self.fields[update_key] = forms.BooleanField(
156 required=False,
157 label=f"Update {key} from {getattr(instance, key)} to {value}",
158 )
160 self.fields[key] = forms.CharField(initial=value, required=False)
161 self.fields[key].widget = self.fields[key].hidden_widget()
162 self.helper = FormHelper()
163 self.helper.add_input(Submit("submit", "Submit"))