Coverage for apis_core/apis_relations/forms.py: 34%
83 statements
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-20 09:24 +0000
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-20 09:24 +0000
1import copy
3from crispy_forms.helper import FormHelper
4from dal import autocomplete
5from django import forms
6from django.conf import settings
7from django.contrib.contenttypes.models import ContentType
8from django.db.models import Q
9from django.urls import reverse
10from django_tables2 import RequestConfig
12from apis_core.apis_entities.autocomplete3 import (
13 PropertyAutocomplete,
14)
15from apis_core.apis_entities.fields import ListSelect2
16from apis_core.apis_entities.utils import get_entity_classes
17from apis_core.apis_metainfo.models import Uri
18from apis_core.apis_relations.models import TempTriple
19from apis_core.utils.settings import get_entity_settings_by_modelname
21from .tables import get_generic_triple_table
24class GenericTripleForm(forms.ModelForm):
25 # TODO RDF : Add Notes and references
27 class Meta:
28 model = TempTriple
29 fields = [
30 "subj",
31 "obj",
32 "prop",
33 "start_date_written",
34 "end_date_written",
35 "notes",
36 ]
37 widgets = {
38 "subj": forms.HiddenInput(),
39 "obj": forms.HiddenInput(),
40 "prop": forms.HiddenInput(),
41 }
43 def __init__(self, entity_type_self_str, entity_type_other_str):
44 super().__init__()
46 self.helper = FormHelper()
47 self.helper.form_tag = False
49 attrs = {
50 "data-placeholder": "Type to get suggestions",
51 "data-minimum-input-length": getattr(settings, "APIS_MIN_CHAR", 3),
52 "data-html": True,
53 "style": "width: 100%",
54 }
55 help_text_other_entity = (
56 "Search and select or use an URL from a reference resource"
57 )
58 attrs_target = copy.deepcopy(attrs)
59 attrs_target["data-tags"] = "1"
61 contenttypes = [
62 ContentType.objects.get_for_model(model) for model in get_entity_classes()
63 ]
64 ct = next(
65 filter(lambda x: x.model == entity_type_other_str.lower(), contenttypes)
66 )
67 url = reverse("apis_core:generic:autocomplete", args=[ct]) + "?create=True"
69 self.fields["other_entity"] = autocomplete.Select2ListCreateChoiceField(
70 label="entity",
71 widget=ListSelect2(
72 url=url,
73 attrs=attrs_target,
74 ),
75 help_text=help_text_other_entity,
76 )
78 # This assert only serves as a linking for us devs, to make explicit what internal object the class
79 # Select2ListCreateChoiceField object afterwards uses.
80 assert PropertyAutocomplete
82 self.fields["property"] = autocomplete.Select2ListCreateChoiceField(
83 label="property",
84 widget=ListSelect2(
85 url=reverse(
86 "apis_core:apis_relations:generic_property_autocomplete",
87 kwargs={
88 "entity_self": entity_type_self_str,
89 "entity_other": entity_type_other_str,
90 },
91 ),
92 attrs=attrs_target,
93 ),
94 )
95 self.helper.include_media = False
97 def load_subj_obj_prop(
98 self,
99 entity_instance_self,
100 entity_instance_other,
101 property_instance,
102 property_direction,
103 ):
104 # the more important function here when writing data from an user input via an ajax call into this form.
105 # Because here the direction of the property is respected. Hence the subject and object position of the
106 # triple and the property name_forward or name_reverse are loaded correctly here.
108 if property_direction == PropertyAutocomplete.SELF_SUBJ_OTHER_OBJ_STR:
109 triple_subj = entity_instance_self
110 triple_obj = entity_instance_other
111 property_direction_name = property_instance.name_forward
113 elif property_direction == PropertyAutocomplete.SELF_OBJ_OTHER_SUBJ_STR:
114 triple_subj = entity_instance_other
115 triple_obj = entity_instance_self
116 property_direction_name = property_instance.name_reverse
118 else:
119 raise Exception("No valid property direction given.")
121 self.fields["subj"].initial = triple_subj
122 self.fields["obj"].initial = triple_obj
123 self.fields["prop"].initial = property_instance
125 property_initial_value = (
126 f"id:{property_instance.pk}__direction:{property_direction}",
127 property_direction_name,
128 )
129 self.fields["property"].initial = property_initial_value
130 self.fields["property"].choices = [property_initial_value]
132 other_entity_initial_value = (
133 str(
134 Uri.objects.filter(
135 root_object=entity_instance_other,
136 ).first()
137 ),
138 f"<span ><small>db</small> {str(entity_instance_other)}</span>",
139 )
140 self.fields["other_entity"].initial = other_entity_initial_value
141 self.fields["other_entity"].choices = [other_entity_initial_value]
143 def load_remaining_data_from_triple(self, triple):
144 # Most data is loaded via the set_subj_obj function.
145 # Here, load the rest from a pre-existing triple.
146 #
147 # This function is both used in get_form_ajax and save_form_ajax,
148 # hence it's not feasible to assume existing user input as done
149 # in 'load_remaining_data_from_input'
151 self.fields["start_date_written"].initial = triple.start_date_written
152 self.fields["end_date_written"].initial = triple.end_date_written
153 self.fields["notes"].initial = triple.notes
154 self.instance = triple
156 def load_remaining_data_from_input(
157 self,
158 start_date_written,
159 end_date_written,
160 ):
161 # Most data is loaded via the set_subj_obj function.
162 # Here, load the rest from the user input via the ajax post
164 self.fields["start_date_written"].initial = start_date_written
165 self.fields["end_date_written"].initial = end_date_written
167 def save(self):
168 if self.instance.pk is None:
169 self.instance = TempTriple.objects.create(
170 subj=self.fields["subj"].initial,
171 obj=self.fields["obj"].initial,
172 prop=self.fields["prop"].initial,
173 )
175 else:
176 self.instance.subj = self.fields["subj"].initial
177 self.instance.obj = self.fields["obj"].initial
178 self.instance.prop = self.fields["prop"].initial
180 self.instance.start_date_written = self.fields["start_date_written"].initial
181 self.instance.end_date_written = self.fields["end_date_written"].initial
182 self.instance.notes = self.fields["notes"].initial
183 self.instance.save()
185 return self.instance
187 def get_text_id(self):
188 """
189 Function to retrieve the highlighted text.
190 :return: ID of text that was highlighted
191 """
192 return self.cleaned_data["HL_text_id"][5:]
194 def get_html_table(self, entity_instance_self, entity_instance_other, request):
195 table_class = get_generic_triple_table(
196 other_entity_class_name=entity_instance_other.__class__.__name__.lower(),
197 entity_pk_self=entity_instance_self.pk,
198 detail=False,
199 )
201 table_object = table_class(
202 data=TempTriple.objects.filter(
203 (
204 Q(subj__self_contenttype=entity_instance_other.self_contenttype)
205 & Q(obj=entity_instance_self)
206 )
207 | (
208 Q(obj__self_contenttype=entity_instance_other.self_contenttype)
209 & Q(subj=entity_instance_self)
210 )
211 ),
212 prefix=entity_instance_other.__class__.__name__,
213 request=request,
214 )
215 entity_settings = get_entity_settings_by_modelname(
216 entity_instance_self.__class__.__name__
217 )
218 per_page = entity_settings.get("relations_per_page", 10)
219 RequestConfig(request, paginate={"per_page": per_page}).configure(table_object)
221 return table_object