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

55 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-22 07:51 +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.utils.html import format_html 

8from django.views import View 

9from django.views.generic.edit import FormView 

10 

11from apis_core.apis_entities.forms import EntitiesMergeForm 

12from apis_core.apis_metainfo.models import RootObject 

13from apis_core.generic.helpers import generate_search_filter 

14from apis_core.generic.views import GenericModelMixin 

15 

16 

17class EntitiesDuplicate(GenericModelMixin, PermissionRequiredMixin, View): 

18 permission_action_required = "create" 

19 

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

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

22 newobj = source_obj.duplicate() 

23 

24 messages.success( 

25 request, 

26 format_html( 

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

28 source_obj.get_absolute_url(), 

29 source_obj, 

30 ), 

31 ) 

32 return redirect(newobj.get_edit_url()) 

33 

34 

35class EntitiesMerge(GenericModelMixin, PermissionRequiredMixin, FormView): 

36 permission_action_required = "create" 

37 form_class = EntitiesMergeForm 

38 template_name = "entity_merge.html" 

39 template_name_suffix = "_merge" 

40 

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

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

43 

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

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

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

47 return context 

48 

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

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

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

52 return kwargs 

53 

54 def form_valid(self, form): 

55 obj = self.get_object() 

56 other = form.cleaned_data["uri"] 

57 obj.merge_with([other]) 

58 return super().form_valid(form) 

59 

60 def get_success_url(self): 

61 return self.get_object().get_edit_url() 

62 

63 

64class EntitiesAutocomplete(autocomplete.Select2QuerySetView): 

65 """ 

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

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

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

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

70 approach for every model). 

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

72 contenttype of the results, separated by an underscore. 

73 

74 Example: 

75 Using this endpoint with the parameters: 

76 

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

78 

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

80 and labels. 

81 """ 

82 

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

84 content_type = ContentType.objects.get_for_model(result) 

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

86 

87 def get_queryset(self): 

88 q = Q() 

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

90 for entity in entities: 

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

92 content_type = get_object_or_404( 

93 ContentType, app_label=app_label, model=model 

94 ) 

95 name = ( 

96 RootObject.objects_inheritance.get_queryset()._get_ancestors_path( 

97 content_type.model_class() 

98 ) 

99 ) 

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

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

102 ) 

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