django-spire 0.25.2__py3-none-any.whl → 0.26.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. django_spire/auth/templates/django_spire/auth/element/android_and_chrome_app_install_element.html +33 -0
  2. django_spire/auth/templates/django_spire/auth/element/ios_app_install_element.html +48 -0
  3. django_spire/auth/templates/django_spire/auth/page/auth_page.html +2 -1
  4. django_spire/auth/templates/django_spire/auth/page/login_page.html +2 -0
  5. django_spire/comment/mixins.py +3 -3
  6. django_spire/comment/templates/django_spire/comment/card/comment_list_card.html +8 -5
  7. django_spire/comment/templates/django_spire/comment/form/comment_form.html +3 -3
  8. django_spire/comment/templates/django_spire/comment/form/content/comment_form_content.html +1 -0
  9. django_spire/comment/templates/django_spire/comment/item/comment_item_ellipsis.html +12 -8
  10. django_spire/comment/views.py +8 -8
  11. django_spire/consts.py +1 -1
  12. django_spire/contrib/form/utils.py +3 -3
  13. django_spire/contrib/queryset/filter_tools.py +56 -14
  14. django_spire/contrib/queryset/mixins.py +24 -3
  15. django_spire/contrib/service/django_model_service.py +5 -6
  16. django_spire/core/management/commands/spire_startapp.py +42 -25
  17. django_spire/core/management/commands/spire_startapp_pkg/exceptions.py +5 -0
  18. django_spire/core/management/commands/spire_startapp_pkg/maps.py +64 -32
  19. django_spire/core/management/commands/spire_startapp_pkg/template/app/constants.py.template +1 -0
  20. django_spire/core/management/commands/spire_startapp_pkg/template/app/forms.py.template +4 -0
  21. django_spire/core/management/commands/spire_startapp_pkg/template/app/models.py.template +2 -1
  22. django_spire/core/management/commands/spire_startapp_pkg/template/app/querysets.py.template +15 -6
  23. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/__init__.py.template +1 -0
  24. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/form_urls.py.template +6 -6
  25. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/page_urls.py.template +2 -2
  26. django_spire/core/management/commands/spire_startapp_pkg/template/app/urls/template_urls.py.template +12 -0
  27. django_spire/core/management/commands/spire_startapp_pkg/template/app/views/form_views.py.template +10 -11
  28. django_spire/core/management/commands/spire_startapp_pkg/template/app/views/page_views.py.template +17 -3
  29. django_spire/core/management/commands/spire_startapp_pkg/template/app/views/template_views.py.template +40 -0
  30. django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${form_card_template_name}.html.template +1 -1
  31. django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_base_card_template_name}.html.template +16 -0
  32. django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_items_card_template_name}.html.template +16 -0
  33. django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_table_card_template_name}.html.template +16 -0
  34. django_spire/core/management/commands/spire_startapp_pkg/template/templates/container/${list_container_template_name}.html.template +1 -0
  35. django_spire/core/management/commands/spire_startapp_pkg/template/templates/form/${list_filter_form_template_name}.html.template +30 -0
  36. django_spire/core/management/commands/spire_startapp_pkg/template/templates/item/${item_template_name}.html.template +32 -20
  37. django_spire/core/management/commands/spire_startapp_pkg/template/templates/item/${list_items_template_name}.html.template +3 -0
  38. django_spire/core/management/commands/spire_startapp_pkg/template/templates/page/${detail_page_template_name}.html.template +3 -3
  39. django_spire/core/management/commands/spire_startapp_pkg/template/templates/page/${form_page_template_name}.html.template +2 -2
  40. django_spire/core/management/commands/spire_startapp_pkg/template/templates/page/${list_page_template_name}.html.template +2 -2
  41. django_spire/core/management/commands/spire_startapp_pkg/template/templates/table/${table_row_template_name}.html.template +6 -0
  42. django_spire/core/management/commands/spire_startapp_pkg/template/templates/table/${table_rows_template_name}.html.template +3 -0
  43. django_spire/core/management/commands/spire_startapp_pkg/template/templates/table/${table_template_name}.html.template +6 -0
  44. django_spire/core/management/commands/spire_startapp_pkg/user_input.py +82 -9
  45. django_spire/core/management/commands/spire_startapp_pkg/validator.py +19 -6
  46. django_spire/core/querysets.py +19 -0
  47. django_spire/core/templates/django_spire/badge/base_badge.html +2 -3
  48. django_spire/core/templates/django_spire/base/base.html +1 -0
  49. django_spire/core/templates/django_spire/button/base_button.html +2 -1
  50. django_spire/core/templates/django_spire/card/title_card.html +13 -10
  51. django_spire/core/templates/django_spire/container/container.html +1 -1
  52. django_spire/core/templates/django_spire/filtering/form/base_session_filter_form.html +1 -1
  53. django_spire/core/templates/django_spire/form/field/_base_file_field.html +216 -0
  54. django_spire/core/templates/django_spire/form/field/_multi_checkbox_field.html +52 -0
  55. django_spire/core/templates/django_spire/form/field/base_field.html +128 -0
  56. django_spire/core/templates/django_spire/form/field/char_field.html +1 -0
  57. django_spire/core/templates/django_spire/form/field/color_field.html +1 -0
  58. django_spire/core/templates/django_spire/form/field/date_field.html +1 -0
  59. django_spire/core/templates/django_spire/form/field/datetime_field.html +1 -0
  60. django_spire/core/templates/django_spire/form/field/decimal_field.html +1 -0
  61. django_spire/core/templates/django_spire/form/field/element/select_checkmark_element.html +4 -0
  62. django_spire/core/templates/django_spire/form/field/element/select_down_arrow_element.html +5 -0
  63. django_spire/core/templates/django_spire/form/field/email_field.html +1 -0
  64. django_spire/core/templates/django_spire/form/field/input_field.html +13 -0
  65. django_spire/core/templates/django_spire/form/field/item/select_choice_item.html +15 -0
  66. django_spire/core/templates/django_spire/form/field/item/selected_choice_item.html +5 -0
  67. django_spire/core/templates/django_spire/form/field/list_field.html +112 -0
  68. django_spire/core/templates/django_spire/form/field/multi_file_field.html +90 -0
  69. django_spire/core/templates/django_spire/form/field/multi_select_field.html +155 -0
  70. django_spire/core/templates/django_spire/form/field/number_field.html +11 -0
  71. django_spire/core/templates/django_spire/form/field/password_field.html +1 -0
  72. django_spire/core/templates/django_spire/form/field/radio_field.html +24 -0
  73. django_spire/core/templates/django_spire/form/field/range_field.html +1 -0
  74. django_spire/core/templates/django_spire/form/field/search_and_select_field.html +119 -0
  75. django_spire/core/templates/django_spire/form/field/search_field.html +5 -0
  76. django_spire/core/templates/django_spire/form/field/select_field.html +78 -0
  77. django_spire/core/templates/django_spire/form/field/single_checkbox_field.html +27 -0
  78. django_spire/core/templates/django_spire/form/field/single_file_field.html +90 -0
  79. django_spire/core/templates/django_spire/form/field/telephone_field.html +1 -0
  80. django_spire/core/templates/django_spire/form/field/text_field.html +11 -0
  81. django_spire/core/templates/django_spire/form/field/time_field.html +1 -0
  82. django_spire/core/templates/django_spire/infinite_scroll/base.html +2 -1
  83. django_spire/core/templatetags/model_tags.py +34 -0
  84. django_spire/metric/report/tools.py +0 -2
  85. {django_spire-0.25.2.dist-info → django_spire-0.26.0.dist-info}/METADATA +1 -1
  86. {django_spire-0.25.2.dist-info → django_spire-0.26.0.dist-info}/RECORD +89 -45
  87. django_spire/core/management/commands/spire_startapp_pkg/template/app/tests/test_intelligence/__init__.py.template +0 -0
  88. django_spire/core/management/commands/spire_startapp_pkg/template/templates/card/${list_card_template_name}.html.template +0 -18
  89. {django_spire-0.25.2.dist-info → django_spire-0.26.0.dist-info}/WHEEL +0 -0
  90. {django_spire-0.25.2.dist-info → django_spire-0.26.0.dist-info}/licenses/LICENSE.md +0 -0
  91. {django_spire-0.25.2.dist-info → django_spire-0.26.0.dist-info}/top_level.txt +0 -0
@@ -591,14 +591,24 @@ class TemplatePaths:
591
591
  """
592
592
 
593
593
  detail_card_template_name: str
594
+ detail_container_template_name: str
594
595
  detail_page_template_name: str
595
596
  form_card_template_name: str
597
+ form_container_template_name: str
596
598
  form_page_template_name: str
597
599
  form_template_name: str
598
600
  item_template_name: str
601
+ list_items_card_template_name: str
602
+ list_table_card_template_name: str
599
603
  list_card_template_name: str
604
+ list_container_template_name: str
605
+ list_items_template_name: str
606
+ list_filter_form_template_name: str
600
607
  list_page_template_name: str
601
608
  template_directory_path: str
609
+ table_row_template_name: str
610
+ table_rows_template_name: str
611
+ table_template_name: str
602
612
 
603
613
  @classmethod
604
614
  def build(
@@ -620,15 +630,31 @@ class TemplatePaths:
620
630
  else app_name.lower()
621
631
  )
622
632
 
633
+ list_display_type = (
634
+ user_inputs.get('list_display_type', 'items')
635
+ if user_inputs
636
+ else 'items'
637
+ )
638
+
623
639
  return cls(
624
- detail_card_template_name=app_name.lower() + '_detail_card',
625
- detail_page_template_name=app_name.lower() + '_detail_page',
626
- form_card_template_name=app_name.lower() + '_form_card',
627
- form_page_template_name=app_name.lower() + '_form_page',
628
- form_template_name=app_name.lower() + '_form',
629
- item_template_name=app_name.lower() + '_item',
630
- list_card_template_name=app_name.lower() + '_list_card',
631
- list_page_template_name=app_name.lower() + '_list_page',
640
+ detail_card_template_name='detail_card',
641
+ detail_container_template_name='detail_container',
642
+ detail_page_template_name='detail_page',
643
+ form_card_template_name='form_card',
644
+ form_container_template_name='form_container',
645
+ form_page_template_name='form_page',
646
+ form_template_name='form',
647
+ item_template_name='item',
648
+ list_items_card_template_name=f'list_items_card',
649
+ list_table_card_template_name=f'list_table_card',
650
+ list_card_template_name=f'list_{list_display_type}_card',
651
+ list_container_template_name='list_container',
652
+ list_filter_form_template_name='list_filter_form',
653
+ list_items_template_name='list_items',
654
+ table_row_template_name='row',
655
+ table_rows_template_name='rows',
656
+ table_template_name='table',
657
+ list_page_template_name='list_page',
632
658
  template_directory_path=template_path,
633
659
  )
634
660
 
@@ -747,37 +773,43 @@ class ViewFunctions:
747
773
  View function names.
748
774
 
749
775
  Example:
750
- list_page_view_name: 'list_page_view'
751
- detail_page_view_name: 'detail_page_view'
752
- create_form_view_name: 'create_form_view'
753
- update_form_view_name: 'update_form_view'
754
- delete_form_view_name: 'delete_form_view'
755
- create_modal_form_view_name: 'create_modal_form_view'
756
- update_modal_form_view_name: 'update_modal_form_view'
757
- delete_modal_form_view_name: 'delete_modal_form_view'
776
+ list_view_name: 'list_page_view'
777
+ detail_view_name: 'detail_page_view'
778
+ create_view_name: 'create_form_view'
779
+ update_view_name: 'update_form_view'
780
+ delete_view_name: 'delete_form_view'
781
+ create_modal_view_name: 'create_modal_form_view'
782
+ update_modal_view_name: 'update_modal_form_view'
783
+ delete_modal_view_name: 'delete_modal_form_view'
784
+ list_items_view_name: 'items_view'
785
+ rows_view_name: 'rows_view'
758
786
 
759
787
  """
760
788
 
761
- create_form_view_name: str
762
- create_modal_form_view_name: str
763
- delete_form_view_name: str
764
- delete_modal_form_view_name: str
765
- detail_page_view_name: str
766
- list_page_view_name: str
767
- update_form_view_name: str
768
- update_modal_form_view_name: str
789
+ create_view_name: str
790
+ create_modal_view_name: str
791
+ delete_view_name: str
792
+ delete_modal_view_name: str
793
+ detail_view_name: str
794
+ list_view_name: str
795
+ update_view_name: str
796
+ update_modal_view_name: str
797
+ list_items_view_name: str
798
+ rows_view_name: str
769
799
 
770
800
  @classmethod
771
801
  def build(cls, components: list[str], **_kwargs) -> ViewFunctions:
772
802
  return cls(
773
- create_form_view_name='create_form_view',
774
- create_modal_form_view_name='create_modal_form_view',
775
- delete_form_view_name='delete_form_view',
776
- delete_modal_form_view_name='delete_modal_form_view',
777
- detail_page_view_name='detail_page_view',
778
- list_page_view_name='list_page_view',
779
- update_form_view_name='update_form_view',
780
- update_modal_form_view_name='update_modal_form_view',
803
+ create_view_name='create_view',
804
+ create_modal_view_name='create_modal_view',
805
+ delete_view_name='delete_form_view',
806
+ delete_modal_view_name='delete_modal_view',
807
+ detail_view_name='detail_view',
808
+ list_view_name='list_view',
809
+ update_view_name='update_view',
810
+ update_modal_view_name='update_modal_view',
811
+ rows_view_name='rows_view',
812
+ list_items_view_name='items_view',
781
813
  )
782
814
 
783
815
 
@@ -0,0 +1 @@
1
+ LIST_FILTERING_SESSION_KEY = '${context_single_var}_list_filter'
@@ -16,3 +16,7 @@ class ${form_class_name}(forms.ModelForm):
16
16
  class Meta:
17
17
  model = models.${model_class_name}
18
18
  exclude: ClassVar = []
19
+
20
+
21
+ class ${model_class_name}ListFilterForm(forms.Form):
22
+ search = forms.CharField(required=False)
@@ -5,12 +5,13 @@ from django.urls import reverse
5
5
 
6
6
  from django_spire.contrib.breadcrumb import Breadcrumbs
7
7
  from django_spire.history.mixins import HistoryModelMixin
8
+ from django_spire.history.activity.mixins import ActivityMixin
8
9
 
9
10
  from ${module_path} import querysets
10
11
  from ${module_path}.services.service import ${service_class_name}
11
12
 
12
13
 
13
- class ${model_class_name}(HistoryModelMixin):
14
+ class ${model_class_name}(HistoryModelMixin, ActivityMixin):
14
15
  name = models.CharField(max_length=255)
15
16
  description = models.TextField(default='')
16
17
 
@@ -5,6 +5,8 @@ from typing import TYPE_CHECKING
5
5
  from django.db.models import Q
6
6
 
7
7
  from django_spire.history.querysets import HistoryQuerySet
8
+ from django_spire.contrib.queryset.mixins import SearchQuerySetMixin, \
9
+ SessionFilterQuerySetMixin
8
10
 
9
11
  if TYPE_CHECKING:
10
12
  from django.db.models import QuerySet
@@ -12,9 +14,16 @@ if TYPE_CHECKING:
12
14
  from ${module_path}.models import ${model_class_name}
13
15
 
14
16
 
15
- class ${queryset_class_name}(HistoryQuerySet):
16
- def search(self, search_value: str) -> QuerySet[${model_class_name}]:
17
- return self.filter(
18
- Q(name__icontains=search_value) |
19
- Q(description__icontains=search_value)
20
- )
17
+ class ${queryset_class_name}(
18
+ HistoryQuerySet,
19
+ SearchQuerySetMixin,
20
+ SessionFilterQuerySetMixin
21
+ ):
22
+ def bulk_filter(self, filter_data: dict) -> QuerySet[${model_class_name}]:
23
+ queryset = self
24
+
25
+ search = filter_data.get('search', '')
26
+ if search:
27
+ queryset = queryset.search(search)
28
+
29
+ return queryset
@@ -8,4 +8,5 @@ app_name = '${url_namespace}'
8
8
  urlpatterns = [
9
9
  path('page/', include('${module_path}.urls.page_urls', namespace='page')),
10
10
  path('form/', include('${module_path}.urls.form_urls', namespace='form')),
11
+ path('template/', include('${module_path}.urls.template_urls', namespace='template')),
11
12
  ]
@@ -8,10 +8,10 @@ from ${module_path}.views import form_views
8
8
  app_name = 'form'
9
9
 
10
10
  urlpatterns = [
11
- path('create/', form_views.${create_form_view_name}, name='create'),
12
- path('<int:pk>/update/', form_views.${update_form_view_name}, name='update'),
13
- path('<int:pk>/delete/', form_views.${delete_form_view_name}, name='delete'),
14
- path('create/modal/', form_views.${create_modal_form_view_name}, name='create_modal'),
15
- path('<int:pk>/update/modal/', form_views.${update_modal_form_view_name}, name='update_modal'),
16
- path('<int:pk>/delete/modal/', form_views.${delete_modal_form_view_name}, name='delete_modal'),
11
+ path('create/', form_views.${create_view_name}, name='create'),
12
+ path('<int:pk>/update/', form_views.${update_view_name}, name='update'),
13
+ path('<int:pk>/delete/', form_views.${delete_view_name}, name='delete'),
14
+ path('create/modal/', form_views.${create_modal_view_name}, name='create_modal'),
15
+ path('<int:pk>/update/modal/', form_views.${update_modal_view_name}, name='update_modal'),
16
+ path('<int:pk>/delete/modal/', form_views.${delete_modal_view_name}, name='delete_modal'),
17
17
  ]
@@ -8,6 +8,6 @@ from ${module_path}.views import page_views
8
8
  app_name = 'page'
9
9
 
10
10
  urlpatterns = [
11
- path('list/', page_views.${list_page_view_name}, name='list'),
12
- path('<int:pk>/detail/', page_views.${detail_page_view_name}, name='detail'),
11
+ path('list/', page_views.${list_view_name}, name='list'),
12
+ path('<int:pk>/detail/', page_views.${detail_view_name}, name='detail'),
13
13
  ]
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from django.urls import path
4
+
5
+ from ${module_path}.views import template_views
6
+
7
+
8
+ app_name = 'template'
9
+
10
+ urlpatterns = [
11
+ path('items/', template_views.${list_items_view_name}, name='items'),
12
+ ]
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
23
23
 
24
24
 
25
25
  @permission_required('${permission_prefix}.delete_${model_instance_name}')
26
- def ${delete_modal_form_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
26
+ def ${delete_modal_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
27
27
  ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)
28
28
 
29
29
  form_action = reverse(
@@ -35,7 +35,6 @@ def ${delete_modal_form_view_name}(request: WSGIRequest, pk: int) -> TemplateRes
35
35
  ${context_single_var}.add_activity(
36
36
  user=request.user,
37
37
  verb='deleted',
38
- device=request.device,
39
38
  information=f'{request.user.get_full_name()} deleted a ${model_instance_name}.'
40
39
  )
41
40
 
@@ -52,7 +51,7 @@ def ${delete_modal_form_view_name}(request: WSGIRequest, pk: int) -> TemplateRes
52
51
 
53
52
 
54
53
  @permission_required('${permission_prefix}.delete_${model_instance_name}')
55
- def ${delete_form_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
54
+ def ${delete_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
56
55
  ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)
57
56
 
58
57
  return_url = request.GET.get(
@@ -68,16 +67,16 @@ def ${delete_form_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
68
67
 
69
68
 
70
69
  @permission_required('${permission_prefix}.add_${model_instance_name}')
71
- def ${create_modal_form_view_name}(request: WSGIRequest) -> TemplateResponse:
72
- return _modal_form_view(request)
70
+ def ${create_modal_view_name}(request: WSGIRequest) -> TemplateResponse:
71
+ return _modal_view(request)
73
72
 
74
73
 
75
74
  @permission_required('${permission_prefix}.change_${model_instance_name}')
76
- def ${update_modal_form_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
77
- return _modal_form_view(request, pk)
75
+ def ${update_modal_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
76
+ return _modal_view(request, pk)
78
77
 
79
78
 
80
- def _modal_form_view(request: WSGIRequest, pk: int = 0) -> TemplateResponse:
79
+ def _modal_view(request: WSGIRequest, pk: int = 0) -> TemplateResponse:
81
80
  ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)
82
81
 
83
82
  dg.glue_model_object(request, '${glue_model_key}', ${context_single_var})
@@ -94,12 +93,12 @@ def _modal_form_view(request: WSGIRequest, pk: int = 0) -> TemplateResponse:
94
93
 
95
94
 
96
95
  @permission_required('${permission_prefix}.add_${model_instance_name}')
97
- def ${create_form_view_name}(request: WSGIRequest) -> TemplateResponse:
96
+ def ${create_view_name}(request: WSGIRequest) -> TemplateResponse:
98
97
  return _form_view(request)
99
98
 
100
99
 
101
100
  @permission_required('${permission_prefix}.change_${model_instance_name}')
102
- def ${update_form_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
101
+ def ${update_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
103
102
  return _form_view(request, pk)
104
103
 
105
104
 
@@ -112,7 +111,7 @@ def _form_view(request: WSGIRequest, pk: int = 0) -> TemplateResponse|HttpRespon
112
111
  form = forms.${form_class_name}(request.POST, instance=${context_single_var})
113
112
 
114
113
  if form.is_valid():
115
- ${context_single_var} = form.save()
114
+ ${context_single_var}, _ = ${context_single_var}.services.save_model_obj(**form.cleaned_data)
116
115
  add_form_activity(${context_single_var}, pk, request.user)
117
116
 
118
117
  return redirect(
@@ -4,10 +4,16 @@ from typing import TYPE_CHECKING
4
4
 
5
5
  from django.contrib.auth.decorators import permission_required
6
6
  from django.shortcuts import get_object_or_404
7
+ from django.urls import reverse
7
8
 
8
9
  from django_spire.contrib.generic_views import portal_views
10
+ from django_spire.core.table.enums import ResponsiveMode
11
+ from django_spire.contrib.session.controller import SessionController
12
+
9
13
 
10
14
  from ${module_path} import models
15
+ from ${module_path}.forms import ${model_class_name}ListFilterForm
16
+ from ${module_path}.constants import LIST_FILTERING_SESSION_KEY
11
17
 
12
18
  if TYPE_CHECKING:
13
19
  from django.core.handlers.wsgi import WSGIRequest
@@ -15,7 +21,7 @@ if TYPE_CHECKING:
15
21
 
16
22
 
17
23
  @permission_required('${permission_prefix}.view_${model_instance_name}')
18
- def ${detail_page_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
24
+ def ${detail_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
19
25
  ${context_single_var} = get_object_or_404(models.${model_class_name}, pk=pk)
20
26
 
21
27
  context_data = {
@@ -31,9 +37,17 @@ def ${detail_page_view_name}(request: WSGIRequest, pk: int) -> TemplateResponse:
31
37
 
32
38
 
33
39
  @permission_required('${permission_prefix}.view_${model_instance_name}')
34
- def ${list_page_view_name}(request: WSGIRequest) -> TemplateResponse:
40
+ def ${list_view_name}(request: WSGIRequest) -> TemplateResponse:
41
+ models.${model_class_name}.objects.process_session_filter(
42
+ request=request,
43
+ session_key=LIST_FILTERING_SESSION_KEY,
44
+ form_class=${model_class_name}ListFilterForm,
45
+ )
46
+
35
47
  context_data = {
36
- '${context_plural_var}': models.${model_class_name}.objects.all()
48
+ 'responsive_mode': ResponsiveMode.SCROLL,
49
+ '${context_single_var}_items_endpoint': reverse('${url_reverse_path}:template:items'),
50
+ 'filter_session': SessionController(request, LIST_FILTERING_SESSION_KEY),
37
51
  }
38
52
 
39
53
  return portal_views.list_view(
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from django.contrib.auth.decorators import permission_required
6
+
7
+ from django_spire.contrib.generic_views import portal_views
8
+
9
+ from ${module_path} import models
10
+ from ${module_path}.constants import LIST_FILTERING_SESSION_KEY
11
+ from ${module_path}.forms import ${model_class_name}ListFilterForm
12
+
13
+ if TYPE_CHECKING:
14
+ from django.core.handlers.wsgi import WSGIRequest
15
+ from django.template.response import TemplateResponse
16
+
17
+
18
+ @permission_required('${permission_prefix}.view_${model_instance_name}')
19
+ def ${list_items_view_name}(request: WSGIRequest) -> TemplateResponse:
20
+ sort_field = request.GET.get('sort', 'name')
21
+ sort_direction = request.GET.get('direction', 'asc')
22
+
23
+ ${context_plural_var} = (
24
+ models.${model_class_name}.objects
25
+ .process_session_filter(
26
+ request=request,
27
+ session_key=LIST_FILTERING_SESSION_KEY,
28
+ form_class=${model_class_name}ListFilterForm,
29
+ ).order_by(
30
+ f"{'-' if sort_direction == 'desc' else ''}{sort_field}"
31
+ )
32
+ )
33
+
34
+ return portal_views.infinite_scrolling_view(
35
+ request,
36
+ context_data={'batch_size': 10,},
37
+ queryset=${context_plural_var},
38
+ queryset_name='${context_plural_var}',
39
+ template='${template_directory_path}/table/${table_rows_template_name}.html'
40
+ )
@@ -5,5 +5,5 @@
5
5
  {% endblock %}
6
6
 
7
7
  {% block card_title_content %}
8
- {% include '${template_directory_path}/form/${form_template_name}' %}
8
+ {% include '${template_directory_path}/form/${form_template_name}.html' %}
9
9
  {% endblock %}
@@ -0,0 +1,16 @@
1
+ {% extends 'django_spire/card/title_card.html' %}
2
+
3
+ {% block card_title %}
4
+ ${model_verbose_name_plural}
5
+ {% endblock %}
6
+
7
+ {% block card_button %}
8
+ {% if perms.${permission_prefix}.add_${model_instance_name} %}
9
+ {% url '${url_reverse_path}:form:create' as new_${context_single_var}_url %}
10
+ {% include 'django_spire/button/primary_dark_button.html' with button_text='Add' button_icon='bi bi-plus' button_href=new_${context_single_var}_url %}
11
+ {% endif %}
12
+ {% endblock %}
13
+
14
+ {% block card_title_content %}
15
+ {% include '${template_directory_path}/table/${list_table_card_template_name}.html' with endpoint=${context_single_var}_rows_endpoint %}
16
+ {% endblock %}
@@ -0,0 +1,16 @@
1
+ {% extends 'django_spire/card/title_card.html' %}
2
+
3
+ {% block card_title %}
4
+ ${model_verbose_name_plural}
5
+ {% endblock %}
6
+
7
+ {% block card_button %}
8
+ {% if perms.${permission_prefix}.add_${model_instance_name} %}
9
+ {% url '${url_reverse_path}:form:create' as new_${context_single_var}_url %}
10
+ {% include 'django_spire/button/primary_dark_button.html' with button_text='Add' button_icon='bi bi-plus' button_href=new_${context_single_var}_url %}
11
+ {% endif %}
12
+ {% endblock %}
13
+
14
+ {% block card_title_content %}
15
+ {% include '${template_directory_path}/container/${list_container_template_name}.html' with endpoint=${context_single_var}_items_endpoint %}
16
+ {% endblock %}
@@ -0,0 +1,16 @@
1
+ {% extends 'django_spire/card/title_card.html' %}
2
+
3
+ {% block card_title %}
4
+ ${model_verbose_name_plural}
5
+ {% endblock %}
6
+
7
+ {% block card_button %}
8
+ {% if perms.${permission_prefix}.add_${model_instance_name} %}
9
+ {% url '${url_reverse_path}:form:create' as new_${context_single_var}_url %}
10
+ {% include 'django_spire/button/primary_dark_button.html' with button_text='Add' button_icon='bi bi-plus' button_href=new_${context_single_var}_url %}
11
+ {% endif %}
12
+ {% endblock %}
13
+
14
+ {% block card_title_content %}
15
+ {% include '${template_directory_path}/table/${table_template_name}.html' with endpoint=${context_single_var}_items_endpoint %}
16
+ {% endblock %}
@@ -0,0 +1 @@
1
+ {% extends 'django_spire/container/infinite_scroll_container.html' %}
@@ -0,0 +1,30 @@
1
+ {% extends 'django_spire/filtering/form/base_session_filter_form.html' %}
2
+
3
+ {% load session_tags %}
4
+
5
+ {% block session_filter_key %}{{ filter_session.session_key }}{% endblock %}
6
+
7
+ {% block filter_content %}
8
+ <div
9
+ class="row g-2 mb-2"
10
+ x-data="{
11
+ async init() {
12
+ this.search_field.set_attribute('placeholder', 'Search...')
13
+ },
14
+
15
+ session_controller: new SessionController('{% session_controller_to_json filter_session.session_key %}'),
16
+ search_field: new GlueCharField(
17
+ 'search',
18
+ {
19
+ value: '{{ filter_session.search|default:"" }}',
20
+ label: 'Search',
21
+ name: 'search',
22
+ }
23
+ ),
24
+ }"
25
+ >
26
+ <div class="col-3">
27
+ {% include 'django_glue/form/field/char_field.html' with glue_field='search_field' %}
28
+ </div>
29
+ </div>
30
+ {% endblock %}
@@ -1,24 +1,36 @@
1
- {% extends 'django_spire/item/item.html' %}
1
+ {% extends 'django_spire/item/infinite_scroll_item.html' %}
2
2
 
3
- {% block item_title %}
4
- {% url '${url_reverse_path}:page:detail' pk=${context_single_var}.pk as ${context_single_var}_view_url %}
5
- {% include 'django_spire/element/attribute_element.html' with attribute_title='${model_verbose_name}' attribute_value=${context_single_var}.name attribute_href=${context_single_var}_view_url %}
6
- {% endblock %}
3
+ {% block item_content %}
4
+ <div class="row justify-content-center align-items-center position-relative">
5
+ <div class="col">
6
+ <div class="row justify-content-between align-items-center {% block item_row_content_outer_class %}{% endblock %}">
7
+ <div class="col">
8
+ <div class="row align-items-center {% block item_content_gutter %}g-2{% endblock %}">
9
+ <div class="row mt-3">
10
+ <div class="col-6">
11
+ {% url '${url_reverse_path}:page:detail' pk=${context_single_var}.pk as ${context_single_var}_view_url %}
12
+ {% include 'django_spire/element/attribute_element.html' with attribute_title='${model_verbose_name}' attribute_value=${context_single_var}.name attribute_href=${context_single_var}_view_url %}
13
+ </div>
14
+ <div class="col-6">
15
+ {% include 'django_spire/element/attribute_element.html' with attribute_title='Description' attribute_value=${context_single_var}.description %}
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ <div class="col-auto top-0 end-0 position-absolute position-lg-static pt-2 pt-lg-0">
21
+ {% url '${url_reverse_path}:page:detail' pk=${context_single_var}.pk as ${context_single_var}_view_url %}
7
22
 
8
- {% block item_row_content %}
9
- {% include 'django_spire/element/attribute_element.html' with attribute_title='Description' attribute_value=${context_single_var}.description %}
10
- {% endblock %}
23
+ {% if perms.${permission_prefix}.change_${model_instance_name} %}
24
+ {% url '${url_reverse_path}:form:update' pk=${context_single_var}.pk as ${context_single_var}_edit_url %}
25
+ {% endif %}
11
26
 
12
- {% block item_button %}
13
- {% url '${url_reverse_path}:page:detail' pk=${context_single_var}.pk as ${context_single_var}_view_url %}
27
+ {% if perms.${permission_prefix}.delete_${model_instance_name} %}
28
+ {% url '${url_reverse_path}:form:delete' pk=${context_single_var}.pk as ${context_single_var}_delete_url %}
29
+ {% endif %}
14
30
 
15
- {% if perms.${permission_prefix}.change_${model_instance_name} %}
16
- {% url '${url_reverse_path}:form:update' pk=${context_single_var}.pk as ${context_single_var}_edit_url %}
17
- {% endif %}
18
-
19
- {% if perms.${permission_prefix}.delete_${model_instance_name} %}
20
- {% url '${url_reverse_path}:form:delete' pk=${context_single_var}.pk as ${context_single_var}_delete_url %}
21
- {% endif %}
22
-
23
- {% include 'django_spire/dropdown/ellipsis_dropdown.html' with view_url=${context_single_var}_view_url edit_url=${context_single_var}_edit_url delete_url=${context_single_var}_delete_url %}
24
- {% endblock %}
31
+ {% include 'django_spire/dropdown/ellipsis_dropdown.html' with view_url=${context_single_var}_view_url edit_url=${context_single_var}_edit_url delete_url=${context_single_var}_delete_url %}
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ {% endblock %}
@@ -0,0 +1,3 @@
1
+ {% for ${context_single_var} in ${context_plural_var} %}
2
+ {% include '${template_directory_path}/item/${item_template_name}.html' %}
3
+ {% endfor %}
@@ -1,13 +1,13 @@
1
1
  {% extends 'django_spire/page/full_page.html' %}
2
2
 
3
- {% block page_content %}
3
+ {% block full_page_content %}
4
4
  <div class="row g-3">
5
5
  <div class="col-12">
6
- {% include '${template_directory_path}/card/${detail_card_template_name}' %}
6
+ {% include '${template_directory_path}/card/${detail_card_template_name}.html' %}
7
7
  </div>
8
8
 
9
9
  <div class="col-4">
10
- {% include 'history/card/activity_list_card.html' with activity_log=${context_single_var}.activity_log.prefetch_user %}
10
+ {% include 'django_spire/activity/card/list_card.html' with activity_log=${context_single_var}.activity_log.prefetch_user %}
11
11
  </div>
12
12
  </div>
13
13
  {% endblock %}
@@ -1,12 +1,12 @@
1
1
  {% extends 'django_spire/page/form_full_page.html' %}
2
2
 
3
- {% block page_content %}
3
+ {% block full_page_content %}
4
4
  <form method="post">
5
5
  {% csrf_token %}
6
6
 
7
7
  <div class="row g-3">
8
8
  <div class="col-12">
9
- {% include '${template_directory_path}/card/${form_card_template_name}' %}
9
+ {% include '${template_directory_path}/card/${form_card_template_name}.html' %}
10
10
  </div>
11
11
  </div>
12
12
  </form>
@@ -1,9 +1,9 @@
1
1
  {% extends 'django_spire/page/full_page.html' %}
2
2
 
3
- {% block page_content %}
3
+ {% block full_page_content %}
4
4
  <div class="row">
5
5
  <div class="col-12">
6
- {% include '${template_directory_path}/card/${list_card_template_name}' %}
6
+ {% include '${template_directory_path}/card/${list_card_template_name}.html' %}
7
7
  </div>
8
8
  </div>
9
9
  {% endblock %}
@@ -0,0 +1,6 @@
1
+ {% extends 'django_spire/table/element/row.html' %}
2
+
3
+ {% block table_cell %}
4
+ {# Add a td element for each column header defined in your table.html, e.g. #}
5
+ {# <td>{{ ${context_single_var}.name }}</td> #}
6
+ {% endblock %}
@@ -0,0 +1,3 @@
1
+ {% for ${context_single_var} in ${context_plural_var} %}
2
+ {% include '${template_directory_path}/table/${table_row_template_name}.html' with row=${context_single_var} %}
3
+ {% endfor %}
@@ -0,0 +1,6 @@
1
+ {% extends 'django_spire/table/base.html' %}
2
+
3
+ {% block table_header %}
4
+ {# Add your table's column headers here #}
5
+ {# e.g. {% include 'django_spire/table/element/header.html' with sort_key='name' label='${model_verbose_name} Name' %}#}
6
+ {% endblock %}