Нет описания

utils.py 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. from django.shortcuts import render
  2. from django.contrib import messages
  3. # Create your views here.
  4. from django_filters.views import FilterView
  5. from django.urls import reverse_lazy, reverse
  6. from django.views.generic import (
  7. ListView,
  8. DetailView,
  9. CreateView,
  10. UpdateView,
  11. DeleteView,
  12. )
  13. from django.core.paginator import Paginator
  14. from core.models import MgMasterView, VMasterView, BelMasterView, EMasterView
  15. class ConfigurableCRUDView:
  16. model = None
  17. list_template_name = None
  18. detail_template_name = None
  19. form_template_name = None
  20. confirm_delete_template_name = None
  21. fields = '__all__' # Default to all fields
  22. paginate_by = 10
  23. filterset_class = None
  24. page_title = "Page Title"
  25. create_url_name = None
  26. update_url_name = None
  27. delete_url_name = None
  28. list_url_name = None
  29. config_fields = "all" # "all" or a list of field names to display
  30. config_field_orders = [] # Fields to display first
  31. config_excludes = [] # Fields to exclude
  32. config_readonly_fields = [] # Fields that should be read-only in update view
  33. config_edit_fields = "__all__" # "all" or a list of field names to display
  34. ordering = None
  35. def get_fields(self):
  36. """
  37. Dynamically generate the fields to be displayed in the list view.
  38. - Includes all fields if `config_fields` is set to "all".
  39. - Respects `config_field_orders` and `config_excludes`.
  40. Returns field instances instead of field names.
  41. """
  42. model_fields = {f.name: f for f in self.model._meta.get_fields()}
  43. # Filter based on `config_fields` configuration
  44. fields = []
  45. if self.config_fields != "all":
  46. fields = [model_fields[f] for f in self.config_fields if f in model_fields]
  47. else:
  48. fields = list(model_fields.values())
  49. # pprint("------------------------")
  50. # pprint(f"fields = {fields}")
  51. # Exclude fields specified in `config_excludes`
  52. fields = [f for f in fields if f.name not in self.config_excludes]
  53. # Order fields based on `config_field_orders`
  54. ordered_fields = [f for f in fields if f.name in self.config_field_orders]
  55. remaining_fields = [f for f in fields if f.name not in self.config_field_orders]
  56. # Reorder fields to match the order specified in `config_field_orders`
  57. ordered_field_names = set(self.config_field_orders)
  58. ordered_fields.sort(key=lambda f: self.config_field_orders.index(f.name) if f.name in ordered_field_names else len(ordered_field_names))
  59. return ordered_fields + remaining_fields
  60. def get_breadcrumbs(self, view_type, obj=None):
  61. """
  62. Generate breadcrumbs dynamically based on the view type.
  63. :param view_type: The type of view (list, create, update, detail, delete)
  64. :param obj: The current object (if applicable)
  65. :return: A list of breadcrumb dictionaries
  66. """
  67. breadcrumbs = [
  68. {'label': 'Dashboard', 'url': reverse('dashboard:index')},
  69. {'label': self.page_title, 'url': reverse(self.list_url_name)} if self.list_url_name else None,
  70. ]
  71. if view_type == 'create':
  72. breadcrumbs.append({'label': f'Create {self.model._meta.verbose_name}', 'url': None})
  73. elif view_type == 'update' and obj:
  74. breadcrumbs.append({'label': obj, 'url': reverse(self.update_url_name, kwargs={'pk': obj.pk})})
  75. elif view_type == 'detail' and obj:
  76. breadcrumbs.append({'label': f'Detail of {obj}', 'url': None})
  77. elif view_type == 'delete' and obj:
  78. breadcrumbs.append({'label': f'Delete {obj}', 'url': None})
  79. return [b for b in breadcrumbs if b]
  80. def get_list_view(self):
  81. class ListViewClass(FilterView, ListView):
  82. model = self.model
  83. template_name = self.list_template_name
  84. paginate_by = self.paginate_by
  85. filterset_class = self.filterset_class
  86. ordering = self.ordering
  87. def get_context_data(inner_self, **kwargs):
  88. context = super().get_context_data(**kwargs)
  89. fields = self.get_fields()
  90. context.update({
  91. 'fields': [f for f in fields],
  92. # 'fields': [field for field in self.model._meta.get_fields()],
  93. 'page_title': self.page_title,
  94. 'list_url': self.list_url_name,
  95. 'create_url': self.create_url_name,
  96. 'update_url': self.update_url_name,
  97. 'delete_url': self.delete_url_name,
  98. 'bs': self.get_breadcrumbs('list'),
  99. })
  100. return context
  101. return ListViewClass
  102. def get_detail_view(self):
  103. class DetailViewClass(DetailView):
  104. model = self.model
  105. template_name = self.detail_template_name
  106. def get_context_data(inner_self, **kwargs):
  107. context = super().get_context_data(**kwargs)
  108. context.update({
  109. 'page_title': self.page_title,
  110. 'bs': self.get_breadcrumbs('detail'),
  111. })
  112. return context
  113. return DetailViewClass
  114. def get_create_view(self):
  115. class CreateViewClass(CreateView):
  116. model = self.model
  117. template_name = self.form_template_name
  118. fields = self.config_edit_fields
  119. def form_valid(inner_self, form):
  120. response = super().form_valid(form)
  121. messages.success(inner_self.request, f"{self.model._meta.verbose_name} created successfully!")
  122. return response
  123. def get_success_url(inner_self):
  124. return reverse(self.update_url_name, kwargs={'pk': inner_self.object.pk})
  125. def get_context_data(inner_self, **kwargs):
  126. context = super().get_context_data(**kwargs)
  127. context.update({
  128. 'list_url_name': self.list_url_name,
  129. 'page_title': f"Create {self.model._meta.verbose_name}",
  130. 'bs': self.get_breadcrumbs('update', obj=inner_self.object),
  131. })
  132. return context
  133. return CreateViewClass
  134. def get_update_view(self):
  135. class UpdateViewClass(UpdateView):
  136. model = self.model
  137. template_name = self.form_template_name
  138. fields = self.config_edit_fields
  139. def form_valid(inner_self, form):
  140. response = super().form_valid(form)
  141. messages.success(inner_self.request, f"{self.model._meta.verbose_name} updated successfully!")
  142. return response
  143. def get_form(inner_self, *args, **kwargs):
  144. """
  145. Customize the form to make specified fields read-only.
  146. """
  147. form = super().get_form(*args, **kwargs)
  148. for field_name in self.config_readonly_fields:
  149. if field_name in form.fields:
  150. form.fields[field_name].widget.attrs['readonly'] = True
  151. form.fields[field_name].widget.attrs['style'] = 'background-color: #f9f9f9; cursor: not-allowed;'
  152. form.fields[field_name].disabled = True # Optional: Completely disable the field
  153. return form
  154. def get_success_url(inner_self):
  155. return reverse(self.update_url_name, kwargs={'pk': inner_self.object.pk})
  156. def get_context_data(inner_self, **kwargs):
  157. context = super().get_context_data(**kwargs)
  158. context.update({
  159. 'list_url_name': self.list_url_name,
  160. 'page_title': f"Update {self.model._meta.verbose_name}",
  161. 'bs': self.get_breadcrumbs('update', obj=inner_self.object),
  162. })
  163. return context
  164. return UpdateViewClass
  165. def get_delete_view(self):
  166. class DeleteViewClass(DeleteView):
  167. model = self.model
  168. template_name = self.confirm_delete_template_name
  169. success_url = reverse_lazy(self.delete_url_name)
  170. def get_context_data(inner_self, **kwargs):
  171. context = super().get_context_data(**kwargs)
  172. context.update({
  173. 'list_url_name': self.list_url_name,
  174. 'page_title': f"Delete {self.model._meta.verbose_name}",
  175. 'bs': self.get_breadcrumbs('delete', obj=inner_self.object),
  176. })
  177. return context
  178. return DeleteViewClass
  179. def queryFromMaster(lot_no):
  180. models = [MgMasterView, VMasterView, BelMasterView, EMasterView]
  181. value_to_filter = lot_no
  182. results = []
  183. for model in models:
  184. queryset = model.objects.filter(PRO2=value_to_filter)
  185. results.extend(queryset)
  186. return results