Coverage for apis_core/generic/urls.py: 96%

27 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-09-14 10:55 +0000

1from django.contrib.contenttypes.models import ContentType 

2from django.http import Http404 

3from django.shortcuts import get_object_or_404 

4from django.urls import include, path, register_converter 

5from rest_framework import routers 

6 

7from apis_core.generic import api_views, views 

8 

9from .abc import GenericModel 

10 

11app_name = "generic" 

12 

13 

14class ContenttypeConverter: 

15 """ 

16 A converter that converts from a string representation of a 

17 model (`app_label.model`) to the actual Django model class. 

18 """ 

19 

20 regex = r"\w+\.\w+" 

21 

22 def to_python(self, value): 

23 app_label, model = value.split(".") 

24 contenttype = get_object_or_404(ContentType, app_label=app_label, model=model) 

25 if issubclass(contenttype.model_class(), GenericModel): 

26 return contenttype 

27 raise Http404 

28 

29 def to_url(self, value): 

30 if isinstance(value, ContentType): 

31 return f"{value.app_label}.{value.model}" 

32 if isinstance(value, str): 

33 return value 

34 if issubclass(value, GenericModel): 

35 return value._meta.label_lower 

36 

37 

38register_converter(ContenttypeConverter, "contenttype") 

39 

40router = routers.DefaultRouter() 

41router.register(r"", api_views.ModelViewSet, basename="genericmodelapi") 

42 

43urlpatterns = [ 

44 path("overview/", views.Overview.as_view(), name="overview"), 

45 path( 

46 "<contenttype:contenttype>/", 

47 include( 

48 [ 

49 path("", views.List.as_view(), name="list"), 

50 path("<int:pk>", views.Detail.as_view(), name="detail"), 

51 path("create", views.Create.as_view(), name="create"), 

52 path("delete/<int:pk>", views.Delete.as_view(), name="delete"), 

53 path("update/<int:pk>", views.Update.as_view(), name="update"), 

54 path("duplicate/<int:pk>", views.Duplicate.as_view(), name="duplicate"), 

55 path( 

56 "selectmergeorenrich/<int:pk>", 

57 views.SelectMergeOrEnrich.as_view(), 

58 name="selectmergeorenrich", 

59 ), 

60 path( 

61 "merge/<int:pk>/<int:otherpk>", 

62 views.MergeWith.as_view(), 

63 name="merge", 

64 ), 

65 path("enrich/<int:pk>", views.Enrich.as_view(), name="enrich"), 

66 path("autocomplete", views.Autocomplete.as_view(), name="autocomplete"), 

67 path("import", views.Import.as_view(), name="import"), 

68 path( 

69 "autocomplete/externalonly", 

70 views.Autocomplete.as_view(), 

71 {"external_only": True}, 

72 name="autocompleteexternalonly", 

73 ), 

74 ] 

75 ), 

76 ), 

77 path("api/<contenttype:contenttype>/", include(router.urls)), 

78]