Coverage for apis_core/apis_entities/views.py: 52%

61 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-16 07:42 +0000

1from dal import autocomplete 

2from django.contrib import messages 

3from django.contrib.auth.mixins import PermissionRequiredMixin 

4from django.contrib.contenttypes.models import ContentType 

5from django.db.models import Q 

6from django.shortcuts import get_object_or_404, redirect 

7from django.urls import reverse 

8from django.utils.html import format_html 

9from django.views import View 

10from django.views.generic.edit import FormView 

11 

12from apis_core.apis_entities.forms import EntitiesMergeForm 

13from apis_core.apis_metainfo.models import RootObject 

14from apis_core.generic.helpers import generate_search_filter 

15from apis_core.generic.views import GenericModelMixin, Update 

16 

17 

18class EntitiesUpdate(Update): 

19 def get_context_data(self, *args, **kwargs): 

20 context = super().get_context_data(*args, **kwargs) 

21 context["mergeform"] = EntitiesMergeForm(instance=self.get_object()) 

22 return context 

23 

24 

25class EntitiesDuplicate(GenericModelMixin, PermissionRequiredMixin, View): 

26 permission_action_required = "create" 

27 

28 def get(self, request, *args, **kwargs): 

29 source_obj = get_object_or_404(self.model, pk=kwargs["pk"]) 

30 newobj = source_obj.duplicate() 

31 

32 messages.success( 

33 request, 

34 format_html( 

35 "<a href={}>{}</a> was successfully duplicated to the current object:", 

36 source_obj.get_absolute_url(), 

37 source_obj, 

38 ), 

39 ) 

40 return redirect( 

41 reverse( 

42 "apis_core:apis_entities:generic_entities_edit_view", 

43 kwargs={ 

44 "pk": newobj.id, 

45 "contenttype": newobj.__class__.__name__.lower(), 

46 }, 

47 ) 

48 ) 

49 

50 

51class EntitiesMerge(GenericModelMixin, PermissionRequiredMixin, FormView): 

52 permission_action_required = "create" 

53 form_class = EntitiesMergeForm 

54 template_name = "entity_merge.html" 

55 template_name_suffix = "_merge" 

56 

57 def get_object(self, *args, **kwargs): 

58 return get_object_or_404(self.model, pk=self.kwargs.get("pk")) 

59 

60 def get_context_data(self, *args, **kwargs): 

61 context = super().get_context_data(*args, **kwargs) 

62 context["object"] = self.get_object() 

63 return context 

64 

65 def get_form_kwargs(self, *args, **kwargs): 

66 kwargs = super().get_form_kwargs(*args, **kwargs) 

67 kwargs["instance"] = self.get_object() 

68 return kwargs 

69 

70 def form_valid(self, form): 

71 obj = self.get_object() 

72 other = form.cleaned_data["uri"] 

73 obj.merge_with([other]) 

74 return super().form_valid(form) 

75 

76 def get_success_url(self): 

77 return reverse( 

78 "apis_core:apis_entities:generic_entities_edit_view", 

79 args=[self.get_object().__class__.__name__.lower(), self.get_object().id], 

80 ) 

81 

82 

83class EntitiesAutocomplete(autocomplete.Select2QuerySetView): 

84 """ 

85 This endpoint allows us to use autocomplete over multiple model classes. 

86 It takes a parameter `entities` which is a list of ContentType natural 

87 keys and searches for the query in all instances of those entities 

88 (using `generate_search_filter`, which means it uses a different search 

89 approach for every model). 

90 The return values of the endpoint are then prefixed with the id of the 

91 contenttype of the results, separated by an underscore. 

92 

93 Example: 

94 Using this endpoint with the parameters: 

95 

96 ?entities=apis_ontology.person&entities=apis_ontology.place&q=ammer 

97 

98 gives you all the persons and places that have `ammer` in their names 

99 and labels. 

100 """ 

101 

102 def get_result_value(self, result) -> str: 

103 content_type = ContentType.objects.get_for_model(result) 

104 return f"{content_type.id}_" + super().get_result_value(result) 

105 

106 def get_queryset(self): 

107 q = Q() 

108 if entities := self.request.GET.getlist("entities"): 

109 for entity in entities: 

110 app_label, model = entity.split(".") 

111 content_type = get_object_or_404( 

112 ContentType, app_label=app_label, model=model 

113 ) 

114 name = ( 

115 RootObject.objects_inheritance.get_queryset()._get_ancestors_path( 

116 content_type.model_class() 

117 ) 

118 ) 

119 q |= Q(**{f"{name}__isnull": False}) & generate_search_filter( 

120 content_type.model_class(), self.q, prefix=f"{name}__" 

121 ) 

122 return RootObject.objects_inheritance.select_subclasses().filter(q)