django-handyhelpers 0.3.18__py3-none-any.whl → 0.3.20__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-handyhelpers
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Summary: A collection of handy utilities to support django operations
5
5
  Home-page: https://github.com/davidslusser/django-handyhelpers
6
- Download-URL: https://github.com/davidslusser/django-handyhelpers/archive/0.3.18.tar.gz
6
+ Download-URL: https://github.com/davidslusser/django-handyhelpers/archive/0.3.20.tar.gz
7
7
  Author: David Slusser
8
8
  Author-email: dbslusser@gmail.com
9
9
  License: GPL-3.0
@@ -1,4 +1,4 @@
1
- handyhelpers/__init__.py,sha256=ywpz4Z6AtaEMPtWFhfvF3pG0zwn1Nhb4kHjbUyP7HbU,406
1
+ handyhelpers/__init__.py,sha256=K3oKhpJJHJk0Dorla4DSbV2WCL9p9ecv3-AB9tgleLM,406
2
2
  handyhelpers/apps.py,sha256=g6mXn-5BENf48vY_Qz2FhAABJPBB3EIJXlNM33v6-v8,485
3
3
  handyhelpers/checks.py,sha256=8LXb106sIBNV3fNIHDIW-UcixJk8emgbtFkIlKG5ZGM,578
4
4
  handyhelpers/context_processors.py,sha256=31-j4WD-xaJp9JU_VbkbyUyWxI2UuDGW9qA805fEGBs,527
@@ -6398,8 +6398,9 @@ handyhelpers/templates/handyhelpers/generic/bs5/partials/pagination_controls.htm
6398
6398
  handyhelpers/templates/handyhelpers/htmx/bs5/about_project_modal_body.htm,sha256=H2OhlHSJObkre_PlkJe_A1ybNAPF2VAVmBtl3HLxmgk,1212
6399
6399
  handyhelpers/templates/handyhelpers/htmx/bs5/generic_modal.htm,sha256=Ttvswnu622audzG5Gl7zikY4KB-4cNcVm6wnWJInZAU,658
6400
6400
  handyhelpers/templates/handyhelpers/htmx/bs5/generic_modal_swap.htm,sha256=NOAScjA1R62Shmrf8uRklRa32LU30nhkopU0ccCjz8c,1826
6401
- handyhelpers/templates/handyhelpers/htmx/bs5/navigation/build_sidebar.htm,sha256=cjRoU4yH3xTsJ40J9mxQ2MdFL0aNdOMyUfO9DgwS8hE,1285
6401
+ handyhelpers/templates/handyhelpers/htmx/bs5/navigation/build_sidebar.htm,sha256=6BuqpRbrChQCVHUEzknVd74vxXpyPf2YYMq1e5LawEU,1757
6402
6402
  handyhelpers/templates/handyhelpers/htmx/bs5/navigation/sidebar_menu_sub_items.htm,sha256=-Hc0qxWK_vWCYW8T52NV7yvnvJA4-cfRdS5DaWWvx9k,152
6403
+ handyhelpers/templates/handyhelpers/partials/calendar.htm,sha256=4UZMT2CzkoxivpJxNhPshMk6EFb0q_bcZzvQXgRKFzM,5141
6403
6404
  handyhelpers/templates/handyhelpers/report/theme_colors.htm,sha256=Jl31SW6o_2lGctKY2gz9INKFs7REC7FSqLtkqHfLOBY,1164
6404
6405
  handyhelpers/templates/handyhelpers/report/chartjs/annual_progress.html,sha256=M9UISiqHR4HaiMD7f0FXHpOUwfmsgwjA8up1pnkCckU,323
6405
6406
  handyhelpers/templates/handyhelpers/report/chartjs/annual_progress_chart.htm,sha256=HHlHOKsz7-wHPZVDFVil4uYm6caKAj2VoN4kBNs4oQ8,2294
@@ -6426,12 +6427,13 @@ handyhelpers/views/__init__.py,sha256=09jR-Yd1mhJqfzzoW5bNTum-KLI35OASqo7-8FQmKI
6426
6427
  handyhelpers/views/action.py,sha256=bJZ-F5U6fcoTjxRxkYO1p7-Va4nBet4qfbG5J6WpHyI,1229
6427
6428
  handyhelpers/views/ajax.py,sha256=wbBcl7aORR6OXS9eApdWy1aoFNeYLOJJx4repBVTGZQ,936
6428
6429
  handyhelpers/views/auditlog.py,sha256=uwcLUCbmQf7vIKu9QGpt4bNXuKY79TmPxZLC7ICdjvk,1151
6430
+ handyhelpers/views/calendar.py,sha256=u3rm8CXYqcFESoNTGUs9Jhi6a8_pcpKCFdIzBYWpISE,3768
6429
6431
  handyhelpers/views/export.py,sha256=45DP5d8L1npo39WqAqYqAnAaNthN5ILyQMIS8WWn85c,3128
6430
6432
  handyhelpers/views/gui.py,sha256=cPGbMu8-dE7MgYleBiPf3YLX_5AsWVtiu1s6MtEDaoo,43358
6431
- handyhelpers/views/htmx.py,sha256=18sKeY92s5VOYZcQzibPkWXPewnF9ciVQlwRw4QyWTw,6029
6433
+ handyhelpers/views/htmx.py,sha256=FWjHj7nexoy0W26LKuTi2HAW6ZiiNhHoNbOYY_apwTQ,6071
6432
6434
  handyhelpers/views/report.py,sha256=1khoo_eEmKLszGEP3sRYqBaKeK-ndbMfahDq7SMRnQI,14898
6433
- django_handyhelpers-0.3.18.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
6434
- django_handyhelpers-0.3.18.dist-info/METADATA,sha256=8kusHXhvuc1RCLsEFCvskyoal2murU2atmF8iWzVWRg,3327
6435
- django_handyhelpers-0.3.18.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6436
- django_handyhelpers-0.3.18.dist-info/top_level.txt,sha256=qMQVRQqXX1vYNEfuQbwWMu2J-GLo_bfLmF6mtZF5caU,13
6437
- django_handyhelpers-0.3.18.dist-info/RECORD,,
6435
+ django_handyhelpers-0.3.20.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
6436
+ django_handyhelpers-0.3.20.dist-info/METADATA,sha256=dVrUNIFPy7rjk5piy5a4yMuy0nIKakvXuZBoZKmsxMs,3327
6437
+ django_handyhelpers-0.3.20.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6438
+ django_handyhelpers-0.3.20.dist-info/top_level.txt,sha256=qMQVRQqXX1vYNEfuQbwWMu2J-GLo_bfLmF6mtZF5caU,13
6439
+ django_handyhelpers-0.3.20.dist-info/RECORD,,
handyhelpers/__init__.py CHANGED
@@ -7,7 +7,7 @@ A collection of handy utilities to support django operations.
7
7
  """
8
8
 
9
9
  __title__ = 'django-handyhelpers'
10
- __version__ = '0.3.18'
10
+ __version__ = '0.3.20'
11
11
  __author__ = 'David Slusser'
12
12
  __email__ = 'dbslusser@gmail.com'
13
13
  __license__ = 'GPL-3.0'
@@ -9,6 +9,15 @@ Build dropdown navigations in a sidebar. This is intented to be used with the ha
9
9
  {{ item.model_name|title }}
10
10
  </a>
11
11
  <ul id="{{ item.target_id }}" class="sidebar-dropdown list-unstyled collapse" data-bs-parent="#sidebar">
12
+ {% if item.list_all_url %}
13
+ <li class="sidebar-link">
14
+ {% if item.htmx_link is False %}
15
+ <a href="{{ item.list_all_url}}" class="sidebar-link ms-4">All {{ item.model_name }}</a>
16
+ {% else %}
17
+ <a hx-get="{{ item.list_all_url }}" hx-target="#{{ item.htmx_target }}" class="sidebar-link ms-4">All {{ item.model_name }}</a>
18
+ {% endif %}
19
+ </li>
20
+ {% endif %}
12
21
  {% for row in item.queryset %}
13
22
  <li class="sidebar-link">
14
23
  {% if item.link %}
@@ -0,0 +1,126 @@
1
+
2
+ <style>
3
+ /* Add custom styles if needed */
4
+ /* Customize the calendar container */
5
+ .calendar-container {
6
+ margin-top: 1.5rem;
7
+ margin-bottom: 1.5rem;
8
+ padding-left: 3rem;
9
+ padding-right: 3rem;
10
+ }
11
+ /* Customize the navigation links */
12
+ .nav-links {
13
+ margin-bottom: 10px;
14
+ }
15
+ /* Customize the calendar table */
16
+ .calendar-table {
17
+ width: 100%;
18
+ border-collapse: collapse;
19
+ }
20
+ .calendar-table th {
21
+ border: 1px solid #dee2e6;
22
+ padding: 8px;
23
+ text-align: center;
24
+ height: 1rem; /* Set fixed height for header row cells */
25
+ }
26
+ .calendar-table td {
27
+ border: 1px solid #dee2e6;
28
+ padding: 8px;
29
+ text-align: center;
30
+ width: 80px; /* Set fixed width for all cells except header row */
31
+ height: 80px; /* Set fixed height for all cells except header row */
32
+ }
33
+ /* Highlight today's date with a different background color */
34
+ .today {
35
+ background-color: var(--bg-light-subtle) !important; /* Change to your desired background color */
36
+ }
37
+ /* Styling for events */
38
+ .event {
39
+ background-color: #007bff; /* Bootstrap primary color */
40
+ color: #fff; /* White text color */
41
+ padding: 4px;
42
+ border-radius: 4px;
43
+ margin-top: 2px;
44
+ font-size: .75rem;
45
+ margin-left: .75rem;
46
+ margin-right: .75rem;
47
+ {% comment %} cursor: pointer; {% endcomment %}
48
+ }
49
+ .cursor-pointer{
50
+ cursor: pointer;
51
+ }
52
+ </style>
53
+
54
+ <div class="container-fluid calendar-container">
55
+ <div class="h2 mt-5 text-primary text-center fw-bold">{{ title }}</div>
56
+ <div class="h4 mb-3 text-secondary text-center">{{ month_name }} {{ year }}</div>
57
+ <div class="text-end nav-links">
58
+ <a
59
+ {% if use_htmx %}
60
+ hx-get="{{ today_url }}" hx-target="#body_main"
61
+ {% else %}
62
+ href="{{ today_url }}"
63
+ {% endif %}
64
+ class="me-3" style="text-decoration: none">
65
+ today
66
+ </a>
67
+ <a
68
+ {% if use_htmx %}
69
+ hx-get="{{ prev_month_url }}" hx-target="#body_main"
70
+ {% else %}
71
+ href="{{ prev_month_url }}"
72
+ {% endif %}
73
+ class="me-2" title="previous month">
74
+ <i class="fa-solid fa-angle-left"></i>
75
+ </a>
76
+ <a
77
+ {% if use_htmx %}
78
+ hx-get="{{ next_month_url }}" hx-target="#body_main"
79
+ {% else %}
80
+ href="{{ next_month_url }}"
81
+ {% endif %}
82
+ class="ms-2" title="next month">
83
+ <i class="fa-solid fa-angle-right"></i>
84
+ </a>
85
+ </div>
86
+ <table class="table table-bordered calendar-table shadow">
87
+ <thead>
88
+ <tr>
89
+ <th class="bg-light-subtle" scope="col">Mon</th>
90
+ <th class="bg-light-subtle" scope="col">Tue</th>
91
+ <th class="bg-light-subtle" scope="col">Wed</th>
92
+ <th class="bg-light-subtle" scope="col">Thu</th>
93
+ <th class="bg-light-subtle" scope="col">Fri</th>
94
+ <th class="bg-light-subtle" scope="col">Sat</th>
95
+ <th class="bg-light-subtle" scope="col">Sun</th>
96
+ </tr>
97
+ </thead>
98
+ <tbody>
99
+ {% for week in cal_data %}
100
+ <tr>
101
+ {% for day in week %}
102
+ <td {% if day == today.day and month == today.month and year == today.year %}class="today"{% endif %}>
103
+ {% if day %}
104
+ <div class="text-end {% if day == today.day and month == today.month and year == today.year %}fw-bold{% endif %}">{{ day }}</div>
105
+ {%endif%}
106
+ {% for event in event_list %}
107
+ {% if event.date_time.day == day and event.date_time.month == month and event.date_time.year == year %}
108
+ {% if event_detail_url %}
109
+ <div class="event hvr-grow d-block cursor-pointer"
110
+ hx-get="{% url event_detail_url event.pk %}"
111
+ hx-target="#modal_wrapper"
112
+ data-bs-toggle="modal"
113
+ data-bs-target="#modal_wrapper">{{ event }}
114
+ </div>
115
+ {% else %}
116
+ <div class="event">{{ event }}</div>
117
+ {% endif %}
118
+ {% endif %}
119
+ {% endfor %}
120
+ </td>
121
+ {% endfor %}
122
+ </tr>
123
+ {% endfor %}
124
+ </tbody>
125
+ </table>
126
+ </div>
@@ -0,0 +1,104 @@
1
+ import calendar
2
+ from datetime import date
3
+ import re
4
+
5
+ from django.shortcuts import render
6
+ from django.views.generic import View
7
+
8
+
9
+
10
+ class CalendarView(View):
11
+ """ View to render a monthly calendar and optionally display events.
12
+
13
+ class parameters:
14
+ template_name - template used when rendering partial; defaults to: handyhelpers/partials/calendar.htm
15
+ event_model - django model representing events
16
+ event_model_date_field - date or datetime field containing event date
17
+ event_detail_url - url to use to get event details and display in a modal
18
+ use_htmx - boolean representing option to use htmx in in today/next month/previous month links
19
+
20
+ Usage Example:
21
+ class MyEventCalendarView(CalendarView):
22
+ event_model = Event
23
+ event_model_date_field = "date"
24
+ event_detail_url = "myapp_:get_event_details"
25
+ """
26
+ title = "Calendar"
27
+ event_model = None
28
+ event_model_date_field = None
29
+ event_detail_url = None
30
+ template_name = "handyhelpers/partials/calendar.htm"
31
+ use_htmx = True
32
+
33
+ def get_next(self, this_year:int, this_month:int) -> tuple:
34
+ """get the year and month of the next month
35
+
36
+ Args:
37
+ this_year (int): year of the currently rendered calendar
38
+ this_month (int): month of the currently rendered calendar
39
+
40
+ Returns:
41
+ tuple: tuple of integers containing year and month of the next calendar month
42
+ """
43
+ if this_month == 12:
44
+ return (this_year + 1), 1
45
+ return this_year, this_month + 1
46
+
47
+ def get_previous(self, this_year:int, this_month:int) -> tuple:
48
+ """get the year and month of the previous month
49
+
50
+ Args:
51
+ this_year (int): year of the currently rendered calendar
52
+ this_month (int): month of the currently rendered calendar
53
+
54
+ Returns:
55
+ tuple: tuple of integers containing year and month of the next calendar month
56
+ """
57
+ if this_month == 1:
58
+ return this_year - 1, 12
59
+ return this_year, this_month - 1
60
+
61
+ def get(self, request, *args, **kwargs):
62
+ mo = re.search(r"^(/[^/]+/)", request.path)
63
+ if mo:
64
+ calendar_url_root = mo.groups()[0]
65
+
66
+ today = date.today()
67
+ year = kwargs.get("year", today.year)
68
+ month = kwargs.get("month", today.month)
69
+ if year == 0:
70
+ year = today.year
71
+ if month == 0:
72
+ month = today.month
73
+ next_year, next_month = self.get_next(year, month)
74
+ prev_year, prev_month = self.get_previous(year, month)
75
+
76
+ today_url = f"{calendar_url_root}{today.year}/{today.month}"
77
+ prev_month_url = f"{calendar_url_root}{prev_year}/{prev_month}"
78
+ next_month_url = f"{calendar_url_root}{next_year}/{next_month}"
79
+
80
+ cal_data = calendar.monthcalendar(year, month)
81
+
82
+ queryset = None
83
+ if self.event_model:
84
+ queryset = self.event_model.objects.filter(
85
+ **{f"{self.event_model_date_field}__year": year,
86
+ f"{self.event_model_date_field}__month": month,
87
+ }
88
+ )
89
+
90
+ context = {
91
+ "cal_data": cal_data,
92
+ "title": self.title,
93
+ "year": year,
94
+ "month": month,
95
+ "month_name": calendar.month_name[month],
96
+ "today": today,
97
+ "event_list": queryset,
98
+ "use_htmx": self.use_htmx,
99
+ "event_detail_url": self.event_detail_url,
100
+ "today_url": today_url,
101
+ "prev_month_url": prev_month_url,
102
+ "next_month_url": next_month_url,
103
+ }
104
+ return render(request, self.template_name, context)
@@ -123,6 +123,7 @@ class BuildModelSidebarNav(HtmxViewMixin, View):
123
123
  {"queryset": MyModelOne.objects.filter(enabled=True),
124
124
  "icon": '<i class="fa-solid fa-people-group"></i>',
125
125
  "htmx_link": False,
126
+ "list_all_url": "list_mymodelones",
126
127
  },
127
128
  ]
128
129
  """
@@ -144,7 +145,7 @@ class BuildModelSidebarNav(HtmxViewMixin, View):
144
145
  item["link"] = hasattr(queryset.model, "get_absolute_url")
145
146
  if item.get("htmx_link", True) and not item.get("htmx_target", None):
146
147
  item["htmx_target"] = "body_main"
147
- self.context = dict(
148
+ context = dict(
148
149
  menu_item_list=self.menu_item_list,
149
150
  )
150
- return render(request, self.template_name, self.context)
151
+ return render(request, self.template_name, context)